Почему компилятор Kotlin требует явного инициализатора свойства var?

Я не могу понять следующую часть документации Котлина:

The initializer, getter and setter are optional. Property type is optional if it can be inferred from the initializer or from the base class member being overridden. Examples: var allByDefault: Int? // error: explicit initializer required, default getter and setter implied 

Единственное объяснение того, почему компилятор требует здесь явного инициализатора (по крайней мере, единственное объяснение, которое я могу придумать), заключается в том, что у Kotlin нет значений свойств по умолчанию. Это правильно? Если да, то почему? Другими словами: в чем разница между свойствами Kotlin и полями Java (которые имеют значения по умолчанию), что не позволяет нам иметь значения свойств по умолчанию?

Это просто: в Java значения по умолчанию равны 0 (ноль) и null . Но в Kotlin большинство значений не являются нулевыми, поэтому вы не можете инициализировать их с помощью null . Для примитивных значений может существовать стратегия инициализации по умолчанию с нулями, но она не была выполнена, чтобы быть последовательной. Но в примитивных массивах значение по умолчанию равно нулю.

Если вам действительно нужна эта семантика инициализации, взгляните на свойства lateinit : https://kotlinlang.org/docs/reference/properties.html#late-initialized-properties .

Этот механизм в принципе позволяет инициализировать поле с null , но затем освобождает вас от нулевых утверждений.

Сложение

На самом деле Котлин очень умный об инициализации. Например, это работает:

 val x: Int if(something) x = 1 else x = 2 println(x) 

Здесь kotlinc может предположить, что x инициализируется до его использования, поэтому код в порядке

Котлин ничего не делает неявным образом. Он не преобразует числовые типы без вашей конкретной инструкции и не устанавливает значение по умолчанию или инициализацию без его явного. Это выбор дизайна для устранения распространенных ошибок, которые были обнаружены в типичных Java-программах. Неясно компилятору, если вы забыли инициализировать его или если вы предназначались для значения по умолчанию, которое будет использоваться. Поскольку это не ясно, это плохо. И поэтому, вероятно, это приводит к ошибкам.

Варианты дизайна Kotlin помогают устранить ошибки из-за кода, в котором компилятор не может определить, есть ли ошибка. Это философский и последовательный язык.

Перед использованием Kotlin требует инициализации. Для членов, которые означают, что к тому времени, когда конструкторы и инициализаторы завершены, он должен иметь значение. lateinit modifier on var позволяет это игнорировать во время компиляции, хотя во время выполнения проверка выполняется при доступе к переменной. Для локальных переменных любая ветвь кода должна инициализировать значение перед доступом. Например:

 fun stateFromAbbreviation(abbreviation: String?): String { val state: String if (abbreviation == null) { state = DEFAULT_STATE } else { state = stateMap.get(abbreviation) ?: throw IllegalStateException("Invalid state abbreviation $abbreviation") } return state } 

Здесь локальная переменная может быть инициализирована в выражении if предполагая, что все ветви инициализируют значение. Но на самом деле этот код был бы более идиоматичным, используя if в качестве выражения, например:

 fun stateFromAbbreviation(abbreviation: String?): String { return if (abbreviation == null) { DEFAULT_STATE } else { stateMap.get(abbreviation) ?: throw IllegalStateException("Invalid state abbreviation $abbreviation") } }