Proposal to disallow class shadowing


#1

Link: http://dotty.epfl.ch/docs/reference/dropped-features/class-shadowing.html

Scala 3 will no longer allow name clashes for nested classes. The following code will cease to compile and will have to be refactored:

class Base {
  class Ops { ... }
}

class Sub extends Base {
  class Ops { ... } // not allowed -- change name (or make private)
}

This compiles in the Scala 2.x series, but leads to confusion and compiler bugs. Usually, when members of classes (such as Ops) have the same name, we’d expect either overriding or overloading to occur. For class members, this is not the case, and the name is shadowed. Thus, forcing unique name choices will both be clearer to the user and much simpler to implement in the compiler.

One question for clarification: will a name clash be allowed for a private class? Technically, those are handled differently (they are not inherited, obviously, and thus do not play part in overriding).


#2

No name clashes would arise from private classes.


#3

In my use-case hiding all ancestors except for the parent class is much less confusing. I won’t be falling on the sword for this feature, but I’ll describe how I use it and why it’s more simple in my case.

I’m using name shadowing in my library to differentiate between a “user” API and a “developer” API, where a user just uses the API of the library and a developer can expand the library by knowing the internals. So I needed a way to clearly separate the two APIs, so the user isn’t exposed to a flood of irrelevant members, but the developer can still access them (both user and developer extend from the library’s traits and classes, so private[Lib] was not enough).

abstract class Foo {
  trait __Dev {
    def devFunc : Unit
  }
  lazy val __dev : __Dev = ???
  def userFunc : Unit ={}
}

class Bar extends Foo {
  trait __Dev extends super[Foo].__Dev {
    def devFunc : Unit = println("only for devs")
  }
  override lazy val __dev : __Dev = new __Dev {}
}

So without shadowing and many extending classes, it the lowest class will now be “flooded” with __DevXXX member traits, instead of a single __Dev. Again, this is not crucial, but it does have its uses.