1

Consider the following Kotlin code:

object Domain {
  val name = "local"
  val location = object {
     val city = "Pittsburgh"
     val state = "Pennsylvania"
  }
}

While this definition is valid and compiles, the following line fails:

val x = Domain.location.city // Error:(30, 27) Kotlin: Unresolved reference: city

However, if we rewrite the above definition as follows:

object City {
    val city = "Pittsburgh"
    val state = "Pennsylvania"
}
object Domain {
    val name = "local"
    val location = City
}

val x = Domain.location.city    // works fine

My question: is this really correct behavior according to the language spec? This doesn't seem sensible or consistent. It makes it inconvenient to declare complex singleton object declarations without breaking each child object out into a top-level declaration. It seems like the compiler is creating anonymous types when this syntax is used, however, type of the assigned value is always object when the definition is in a nested context. This almost seems like a type inference bug in the compiler. What am I missing?

LBushkin
  • 129,300
  • 32
  • 216
  • 265
  • Upon further review, it appears that the intended way to create nested object declaration is as follows: `object Foo { val x; object Bar { val y } }` However, since the other syntax exists and produces, somewhat useless behavior, it still seems like it should either compile into the equivalent code, or be disallowed. – LBushkin Aug 23 '19 at 18:15

1 Answers1

3

What creating an anonymous object does is create a class that extends Any. Since no type information can be given except the superclass (in this case, Any), all fields not declared in that superclass will not be visible.

By creating your named object Bar, the class Bar is generated, as are the references to the fields, which is why they are visible in that case.

Nick Johnson
  • 157
  • 12
  • I understand the basic premise of object; the weirdness is that if you declare them as I did in my second example above (two top-level objects with the second referencing the first) sufficient type information is retained to allow references to the fields of the inner object. This seems inconsistent and unexpected. Also, while the alternate syntax works and is less verbose than breaking objects up, it has the downside that code that uses reflection to traverse the members of the anonymous objects doesn't see the nested object properties (since they're not properties but actually nested types). – LBushkin Aug 24 '19 at 01:18
  • I'm not sure why you think that referncing a top level object would not retain enough information to allow accessing its fields. Since it is a named object, it will have a generated class file, keeping all field information and allowing access. When you create an anonymous class, the generated class file keeps no information beyond the supertype information. – Nick Johnson Aug 24 '19 at 16:38