Несогласованная доступность объявлений вложенных объектов в Kotlin

Рассмотрим следующий код Kotlin:

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

Хотя это определение корректно и компилируется, следующая строка завершается ошибкой:

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

Однако, если мы перепишем приведенное выше определение следующим образом:

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

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

Мой вопрос: действительно ли это правильное поведение в соответствии со спецификацией языка? Это не кажется разумным или последовательным. Это делает неудобным объявлять сложные одноэлементные объявления объектов, не разбивая каждый дочерний объект на объявление верхнего уровня. Кажется, что компилятор создает анонимные типы, когда используется этот синтаксис, однако тип присваиваемого значения всегда object, когда определение находится во вложенном контексте. Это почти похоже на ошибку вывода типа в компиляторе. Что мне не хватает?


person LBushkin    schedule 23.08.2019    source источник
comment
При дальнейшем рассмотрении выясняется, что предполагаемый способ создания объявления вложенного объекта выглядит следующим образом: object Foo { val x; object Bar { val y } } Однако, поскольку другой синтаксис существует и приводит к несколько бесполезному поведению, по-прежнему кажется, что он должен либо скомпилироваться в эквивалентный код, либо быть запрещенным. .   -  person LBushkin    schedule 23.08.2019


Ответы (1)


Что делает создание анонимного объекта, так это создает класс, который расширяет Any. Поскольку никакая информация о типе не может быть предоставлена, кроме суперкласса (в данном случае Any), все поля, не объявленные в этом суперклассе, не будут видны.

При создании именованного объекта Bar создается класс Bar, а также ссылки на поля, поэтому в этом случае они видны.

person Nick Johnson    schedule 23.08.2019
comment
Я понимаю основную предпосылку объекта; странность заключается в том, что если вы объявите их, как я сделал во втором примере выше (два объекта верхнего уровня, причем второй ссылается на первый), сохраняется достаточно информации о типе, чтобы разрешить ссылки на поля внутреннего объекта. Это кажется непоследовательным и неожиданным. Кроме того, хотя альтернативный синтаксис работает и является менее подробным, чем разбиение объектов, его недостаток заключается в том, что код, использующий отражение для обхода членов анонимных объектов, не видит свойства вложенных объектов (поскольку они не являются свойствами, а фактически вложенные типы). - person LBushkin; 24.08.2019
comment
Я не уверен, почему вы думаете, что ссылка на объект верхнего уровня не сохранит достаточно информации, чтобы разрешить доступ к его полям. Поскольку это именованный объект, он будет иметь сгенерированный файл класса, содержащий всю информацию о полях и разрешающий доступ. Когда вы создаете анонимный класс, сгенерированный файл класса не содержит никакой информации, кроме информации о супертипе. - person Nick Johnson; 24.08.2019