What should the visibility of x defined a toplevel definition like
package p
private val x = e
be ? Currently it is the package p. But we could also decide that it should be the file in which x appears.
It should have exactly the same visibility as a private class X, obviously. I believe that means only the current file?
No, private class means it's private to the package. But opaque type means opaque to the file.
But maybe one of them should be changed?
Speaking from the peanut gallery -- to me, private to the package seems more intuitively obvious, since my understanding of top-level declarations is that they are generally scoped relative to the package itself. That's not exactly a principled argument, but it's one data point of expectations...
I always thought that private class means private to the file - possibly because in package objects private means private-to-object. Everyone seems to be using private[p] for private to the package.
Hello! Some aggregated thoughts:
In favor of file visibility:
private) and package scope (via private[p])package p1
// Could be useful within package
private[p1] val data = Santa(Country.CH, "Samichlaus") ::
Santa(Country.RU, "Дед Мороз") ::
Nil
// Needed only for 'def santaOf'
private val indexedData = data map (s => s.country -> s) toMap
// Publicly exposed
def santaOf(country: Country): Option[Santa] = indexedData.get(country)
In favor of package visibility:
package object {private ...} and private class behaviourNow, I feel 55%/45% bias towards the file visibility for the top level definitions (including private classes). Looks like small but strategically good change.
We have only two choices:
The reason is that
package p
private val x = e
class C { ... }
is translated to
package p
object ...$package {
private[p] val x = e
}
class C { ... }
We could drop the [p] qualifier from the private, but then it would not be visible in class C.
Arguments in favor of dropping [p]:
private the smallest scope possible.private[p]. Arguments against:
private on toplevel class always means package private, so this would open a discrepancy.My tentative position is that it's better to leave things as they are. I.e. private is package private. But I'm willing to be convinced otherwise.
Relatedly, inclusion of nested things is weird. Here, f is visible in p in the same file, but not compiled separately. f is in the empty package. private makes it inaccessible in p. This exercise helps me not to take textual nesting too literally.
// ok in one compilation unit
def f = "hello, world"
package p {
@main def m = println(f)
}
I recently asked about private[C] in relation to privacy, where C is immediately enclosing, and the suggestion was that private is categorically different. So I'm also prepared to write private[p], where p is immediately enclosing, if that is the different behavior I want.
I'm not sure which emoji reaction to use for the poll, but I vote for changing status quo to "wow, access modifiers are really interesting in Scala 3."
As I said in the beginning, to me it's pretty obvious that a private def needs to have the same visibility as a private class.
Regularity wrt the scope of opaque type aliases would be nice, but infinitely les important than regularity with the visibility of classes.
As I said in the beginning, to me it's pretty obvious that a private def needs to have the same visibility as a private class.
It looks like Scala 2 and 3 don't have the same opinion of where a private class should be visible actually:
// A.scala:
package pkg
private class A
// B.scala:
package pkg
class B extends A
```shell
% scalac A.scala B.scala
Scala 2:
```scala
B.scala:3: error: private class A escapes its defining scope as part of type pkg.A
class B extends A
^
1 error
Scala 3:
-Xprint:typer reveals that private got typed as private[pkg].Oops nevermind, I misread the error which is about the private scope leaking, not about A not being visible. So in both cases A is visible in separate compilation units in the same package.
@odersky
What would stop a third option? — conjure a file-private scope distinct from the synthetic object scope. There's no reason for new features to have to translate directly into existing Scala syntax.
(Actually, such a scope already exists for sealed, just not for visibility)
I agree that private defs should behave like private classes, and private classes should behave like Scala 2. That is what is implemented, so no action is needed.
Most helpful comment
I always thought that
private classmeans private to the file - possibly because in package objects private means private-to-object. Everyone seems to be usingprivate[p]for private to the package.