Inconsistency in nested object types

Consider the following snippet of 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

This seems inconsistent, since in principle the same type information is available in both cases, but when the nested types are declared inline, they are treated as Any instead of as their anonymous type.

Now, we can, of course, write this differently:

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

With this structure, the member access Domain.location.city works just fine. But this declaration is NOT equivalent to the first two. For one thing, the location definition is NOT actually a member of Domain, it is a nested type. This impacts things like reflection and serialization, which don’t see location as a property that can be retrieved. It also means that we cannot declare location to use var and allow it to be mutable/assignable, which we could previously do.

I propose that we improve the design of the language so that in my first example, the types of nested objects are retrained by the compiler (instead of assigning the inner type to Any). Barring this, it should be illegal (i.e. a compile-time error) to declare a nested object inside another object, as the members of the inner nested object cannot be meaningfully accessed (except awkwardly through reflection).

1 Like

It seems a little inconsistent, expecially if you use anonymous objects only. Then it will work correctly :slight_smile:

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

fun main() {
	val x = domain.location.city // no error
}