i needed two instances that has access to each other privates. i naturaly thought of a companion object that grants access to a one and only instance of it’s companion class. the class itself i made private, so users cannot just create instances using new.
object A {
def apply = dual
lazy val dual = new A
}
private class A {
//some irrelevant logic...
}
this code does not compile. i get: class A escapes its defining scope as part of type A error, which i don’t really understand. my current workaround was to define a trait with every method declaration the class should have and make class A extend that trait, while dual is of the trait type, and not class A type.
what’s the theoretic problem i’m missing here? why is this forbiden?
Paolo’s solution is good (+1), but he didn’t explain the error message, so let me try that. The problem stems from the fact that every method needs a return type. Your original definition of
applyanddualreturned an object ofclass A, thus the implicit return type of both wasA. That implies thatAmust be visible to clients – how else could they call the function or access theval? Moreover, as both – and their parent object too – are public, they are globally visible. However, you declaredA privatewhich means it must not be visible outside its package. So there is a conflict which can’t be resolved by the compiler.The general rule is that all parameter and return type of functions / members must have (at least) the same scope of visibility as the referring member itself*. Thus one trivial way to solve this problem would be to reduce the visibility of
applyanddualtoprivate. This would satisfy the compiler, but not you 🙂Your solution gets around the problem by changing the static return type to a
publictrait, which thus has the same visibility as the members referring to it. The dynamic type of the returned object is stillclass A, however, this need not be visible to clients. This is a classic example of the principle “program to interfaces, not implementations”.Note that to apply this principle to the full extent, one could turn
class Ainto aprivateinner class ofobject A, thus making it innaccessible even for other classes within the same package:* To be pedantic, the enclosing class / object may reduce the visibility of its members, like here:
where
memberispublicbut its enclosing class isprivate, effectively hiding its members from the external world. So the compiler emits no complaints here.