Reputation: 36966
I am a java developer and now I am learning Kotlin.
I've met an interesting(working) piece of code:
class C {
private fun getObject() = object {
val x: String = "x"
}
fun printX() {
println(getObject().x)
}
}
But if I remove private
modifier for getObject
method:
class C {
fun getObject() = object {
val x: String = "x"
}
fun printX() {
println(getObject().x)
}
}
The Kotlin complains
Unresolved reference: x
Could you please explain why is it done this way ? From my point of view it looks a bit weird.
Upvotes: 1
Views: 491
Reputation: 28452
Why it doesn't work?
This is because we created an anonymous object/class, so it doesn't have a representation in the type system available to the user. There is no class with x
property, we can only represent this object as Any
. Of course, internally the compiler creates a class with x
, but this class is not visible to us, we can't store such object with its real type in a property, etc.
So why it does work?
Kotlin and some other languages sometimes provide "superpowers" for local code. There are multiple examples of this:
object
members, but only if private.It's hard to provide a simple answer on why we do this. But generally, when we work on local or private code, then we focus on this small fragment of functionality which we consider implementation details of the file or class. Then we often prefer convenience and to be implicit, than keeping the code strict and explicit. If we have to change anything, we do this in a single place.
It is the opposite if components are public. In that case they could be used from tens of places around the code, we can't remember about all of them, so it is safer and easier to maintain if we keep our code more strict, so e.g. create a regular, named class instead of anonymous one.
It is even worse if accessing the code from another module. In that case the compiler doesn't know the full context of the original code, it only sees a method returning a class with some random name. Kotlin could add extra info in the bytecode by using annotations, but Java/JavaScript would ignore them entirely. Also, as we didn't provide a name for the anonymous class, compiler had to auto-generate it. If it'll generate a different name in the future, that will be a binary-incompatible change.
Another potential reason is the complexity for the compiler. To allow such features, the compiler has to keep additional metadata about the code and it has to apply some tricks to "break the rules". If they are allowed only locally, the compiler can do these complex transformations for a single file/class/module at a time, but keep a simpler code representation in general.
Upvotes: 2