Why can't I do this in object expressions?

val helloWorld = object {
    val a = 0
}

private val helloWorld2 = object {
    val a = 0
}

fun main() {
    val helloWorld3 = object {
        val a = 0
    }

    // a1
    println(helloWorld.a)   // no access
    // a2
    println(helloWorld2.a)  // accessible
    // a3
    println(helloWorld3.a)  // accessible
}

Why is it not accessible from “a2”, “a3”?

The page you mention says:

If this function or property is public or private inline, its actual type is:

  • Any if the anonymous object doesn’t have a declared supertype

Hence your helloWorld has type Any.

1 Like

Thank you for your reply :grinning: . But I wonder why there is such a constraint.

No idea, however the usual syntax for defining a singleton is:

object helloWorld {
    val a = 0
}

which works the way you like. And is shorter.

1 Like

Let’s start with why the property is not accessible.

Object expression creates anonymous type. This means not only that this type does not have a name, but it doesn’t at all exist. Well, technically it exists, but not from the user perspective. So if there is no type that can describe what is helloworld, then it can only be Any. In other words: to access a property of some variable, it has to be of type that has a property. But in this case there is no usable type with a property.

If object expression extends from a supertype, then the variable can be of this supertype, because supertype is not anonymous and can be referenced normally. But still, if this object expression adds new members, they won’t be visible, because the type created by the object expression is itself anonymous, so we can only reference members of the supertype.

So… why in some cases this is all not at all true?

My understanding is that this is for user convenience. In some cases Kotlin performs advanced type inference and provides some flexibility to the type system. But, this is usually limited to a more local scope, because it would be too complicated or too error-prone to use it on a wider scale. Smart casts is a good example. They provide additional information to the type system, they even support union types, but this is all local. At the point where we assign such local variable to a property, all this advanced information is lost.

It is similar with object expressions. Kotlin allows to be more flexible if the variable is private, because the risk of doing something bad is relatively low. And it is easier for the compiler to support such case. But if you try to make the variable available from the outside world, you lose this additional flexibility.

3 Likes

@al3c @broot Thank you for taking the time to reply!

Where do you put this code ? It doesn’t work for me in Kotlin/JVM 1.6.10 for a top-level variable or a local variable in function :thinking:

my bad I corrected the example :slight_smile: you need to use object and not val