19

I can't understand the following piece of Kotlin documentation:

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

The only explanation of why the compiler requires explicit initializer here (at least the only explanation I can come up with) is that Kotlin does not have default values of properties. Is it right? If so, why? In other words: what is the difference between Kotlin properties and Java fields (which have default values) which doesn't allow us to have default values of properties?

aga
  • 27,954
  • 13
  • 86
  • 121
  • Did you find a good explanation for your question anywhere ? All that i understood is properties in kotlin should be either initialized or declared as lateinit, with some constraints like lateinit is not allowed for primitive types and also not allowed for nullable types. – K Pradeep Kumar Reddy Jul 24 '20 at 13:23

2 Answers2

14

That's simple: in Java default values are 0 (zero) and null. But in Kotlin most of the values are not-nullable, so you can't initialise them with null. For primitive values there could be a default strategy of initialising with zeros, but it was not done in order to be consistent. But in primitive arrays the default value is zero indeed.

If you really need that initialisation semantic, take a look at lateinit properties: https://kotlinlang.org/docs/reference/properties.html#late-initialized-properties.

That mechanism basically allows to init a field with null, but then frees you from null assertions.

ADDITION

Actually Kotlin is very clever about initialization. For example that works:

val x: Int

if(something)
    x = 1
else
    x = 2

println(x)

Here kotlinc may proove that x is being initialized before it is being used, so the code is OK

voddan
  • 31,956
  • 8
  • 77
  • 87
  • 3
    "But in Kotlin most of the values are not-nullable, so you can't initialise them with null" - I asked specifically about the property declared like so: `var allBeDefaut: Int?`. Clearly, this is the nullable variable and it could be initialized with `null` by default, as opposed to, say, `var someVar: Int`. – aga Nov 17 '15 at 13:12
  • @aga But the consistency is very important. Besides default initialisation is somewhat indirect/invisible, a should be avoided anyway. Almost any use case for that has a more elegant solution – voddan Nov 17 '15 at 14:50
  • And I never saw a good use for default initialisation, in any language that I've worked with – voddan Nov 17 '15 at 14:51
  • `That mechanism basically allows to init a field with null, but then frees you from null assertions.` --- this isn't an accurate description. `lateinit` allows you to leave the property _uninitialized_, deferring initialization until some point that precedes the first derefence. If you dereference it too early, you won't get an NPE but an exception specific to this case: `UninitializedPropertyAccessException` – Marko Topolnik Jul 27 '18 at 18:37
  • I did not understand your explanation. How this code is ok ? val x: Int. I tried this code, without initialization, this will give compiler error saying "property must be initialized or be abstract". And one more thing, x is declared as val, we can not reassign value to it. – K Pradeep Kumar Reddy Jul 24 '20 at 13:08
3

Kotlin does not do anything implicitly. It does not convert numeric types without your specific instruction, nor does it set a default or initializing value without it being explicit. It is a design choice to eliminate common errors that were found in typical Java programs. It isn't clear to the compiler if you forgot to initialize it or if you meant for a default value to be used. Since it isn't clear, it is bad. And therefore likely results in bugs.

The design choices of Kotlin help eliminate bugs due to code in which the compiler cannot help determine if there is an error. It is philosophical and consistent in the language.

Kotlin requires initialization before use. For members that means by the time constructors and initializers are completed, it must have a value. lateinit modifier on var allows this to be ignored at compile time although at runtime the check is done when you access the variable. For local variables, any branch of code must initialize the value before access. For example:

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
}

Here the local variable can be initialized in the if statement assuming all branches initialize the value. But really, this code would be more idiomatic using the if as an expression, such as:

fun stateFromAbbreviation(abbreviation: String?): String {
    return if (abbreviation == null) {
        DEFAULT_STATE
    }
    else {
        stateMap.get(abbreviation) ?: throw IllegalStateException("Invalid state abbreviation $abbreviation")
    }
}
Jayson Minard
  • 84,842
  • 38
  • 184
  • 227