gstackoverflow
gstackoverflow

Reputation: 36966

Why do I can't access to non-private member of anonymous object in Kotlin?

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

Answers (1)

broot
broot

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:

  • Kotlin: as above, access object members, but only if private.
  • Kotlin: smart cast of properties, but only if in a local module.
  • Java: type inference, but only for local vars.
  • Kotlin/Java: intersection types, but only for local vars.
  • Kotlin/Java: access private fields of nested/outer classes.

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

Related Questions