Type members expose privates, values of unmentionable types

ETA: please see clarification here. Original question follows:

I just realized that a type alias can publicize a private type:

object A {
	private[A] object B { def string = "" }
	type Export = () => B.type 
	val export: Export = () => B
}
object C {
	val b = A.export()
	val string = b.string
}

This creates a weird situation: there is no type (other than Any) that I can explicitly write for C.b. The compiler knows what the type is, but I can’t mention it; writing val b: A.B = ... would fail. And I can go on to access methods like B.string that are supposed to be private[A] once I got a reference to B.

Is this intentional? Is it desirable?

1 Like

Interesting case. I’d say this behavior is desirable, because what else should the compiler do? You made the type Export public, and you can’t know what Export is unless you also know what B is.

I’ve narrowed down the problem.

This works: object A { private[A] trait B; def b: B = new B{} }

But this doesn’t: object A { private trait B; def b: B = new B{} }; compilation fails saying private trait B escapes its defining scope as part of type A.B.

The Scala spec on visibility modifiers doesn’t explain why this difference should be relevant. Can someone explain to me why there’s a difference in behavior?

1 Like

Ok, after further consideration, I changed my mind and now I consider the behavior undesirable. Aliases should be required to have the same access restrictions.

The difference between private and private[A] should be access from the companion, but it should not be relevant here.

If you want some interesting reads on this topic you can search the Scala bug tracker for beauties such as this one.

@Jasper-M, wow, thanks. Clearly, I did not suspect the magnitude of the problem.

I wonder if we have consensus on what the desired behavior should be?

How about: never allow a type to escape? Would that work for every one?