Inner object in class cannot close over outer class members

Another question in the same vein of my previous, and linked to it.

The following won’t compile

open class A (val str:String){
    object R {
        //val s1 = str // str is not in scope!
        val s2 = "foo"
    }
    fun foo() {
        val ss = R.s2 // won't compile unless A.R is imported!
    }
}

class B : A(“x”) {
  fun foo() {
  val ss = R.s2 // won’t compile unless A.R is imported!
  }
}


while:

open class A (val str:String){
    val R = object {
        val s = str // compiles
    }
}

class B : A(“x”) {
  fun foo() {
  val ss = R.s2 // won’t compile since A.R is Any
  }
}


So, it looks like inner object declarations are like static members of the class definition; this is consistent with inner class definitions, that require the inner modifier to close over the outer class’ fields; however, there is no inner modifier for object definitions, and object expressions are resolved as Any; do you think part of this behavior may qualify as a bug?

Thanks !

1 Like

In Java and Kotlin, "inner" means "capturing the outer instance", where as "nested" means simply declared inside something else. Java's static classes are only nested, non-static nested classes are inner. In Kotlin you have to explicitly declare something as "inner" (we reversed the Java's convention). So, your object is not inner, btu only nested. And no named object can be inner, in fact: named objects are singletons, so the can not depend on any kind of outer instance.

1 Like

Why can’t an object be declared as inner? What if I really need to attach it to the outer instance?

At first glance, there seems to be a workaround, but it’s a partial one: if we write val R = object { ... } we can access fields of the outer instance, but not vice-versa.

Unfortunately, we cannot apply inner keyword in this way: inner object R { ... } which would be quite natural, no?

Non-anonymous objects are singletons, meaning there is only ever one instance of that class during runtime. How would a singleton switch between the different instance of the outer class?

Non-anonymous objects marked with inner would not be singletons. A new instance of such an object would be created when the outer instance is created. You can call it “context singletons”, meaning that such objects are unique per instance of a host object.

inner object a { ... } is just a shortcut for inner class A { ... }; val a = A();

I see two potential problems at the conceptual level. First, object declarations in Kotlin always meant singletons, so it could be misleading if suddenly they are not necessarily singletons. Second. usually when we reference a class by its name, we mean a static context. Context variables are represented as members. In this case class would work like a member which is pretty inconsistent with the rest of the language design.

What is your use case? Such object would work almost like its properties are part of the outer class. Although, I see some potential benefits here.

Also, please note you can access members of val R = object { ... } if you make it private.

Good reminder about the private access.
Here’s a runnable if anyone wants to mess around with it.

class Foo {
    private val inner = object { val bar = "buzz" }
    init {
        println(inner.bar)
    }
}

fun main() {
    Foo()
}

When namespaces get added I expect a lot of these discussions to change. Instead of trying to make use of objects we’ll have more options that may be a better fit for these use cases.