user16422658
user16422658

Reputation:

Property must be initialised even though type is defined in Kotlin

I am not sure Stack overflow will like this question. I am learning Kotlin and trying to declare a basic variable without any class.

This is the simplest example.

I now understand why the compiler won't accept it, says it must be initialised. But if I put it inside the main function, then it works fine.

I saw this tutorial on W3Schools and it says you dont have to initialise the variable if you declare its type? Well I have and it still is forcing me to initialise it https://www.w3schools.com/kotlin/kotlin_variables.php

enter image description here

It's a simple variable in a file no class:

/**
 * Number types:
 * This is the most important, and we should be able to go over it quick.
 * We start from the smallest to the biggest
 */

var byteEg: Byte;

Even inside a class it doesn't work:

class Variables{
    var byteEg: Byte;
}

When I try latentinit it gives an exception: 'lateinit' modifier is not allowed on properties of primitive types

Upvotes: 0

Views: 669

Answers (2)

gidds
gidds

Reputation: 18567

The general principle is that everything must be initialised before it's used.*

(This is in contrast to languages like C, in which uninitialised values hold random data that could be impossible, invalid, or cause an error if used; and languages like Java, which initialise everything to 0/false/null if you don't specify.)

That can happen in the declaration itself; and that's often the best place. But it's not the only option.

Local variables can be declared without an initialiser, as long as the compiler can confirm that they always get set before they're used. If not, you get a compilation error when you try to use it:

fun main() {
    var byteEg: Byte

    println(byteEg) // ← error ‘Variable 'byteEg' must be initialized’
}

Similarly, class properties can be declared without an initialiser, as long as a constructor or init block always sets them.

In your example, you could set byteEg in a constructor:

class Variables2 {
    var byteEg: Byte

    constructor(b: Byte) {
        byteEg = b
    }
}

Or in an init block:

class Variables {
    var byteEg: Byte

    init {
        byteEg = 1.toByte()
    }
}

But it has to be set at some point during class initialisation. (The compiler is a little stricter about properties, because of the risk of them being accessed by other threads — which doesn't apply to local variables.)

Note that this includes vals as well as vars, as long as the compiler can confirm that they always get set exactly once before they're used. (Kotlin calls this ‘deferred assignment’; in Java, it's called a ‘blank final’.)

As another answer mentions, there's an exception to this for lateinit variables, but those are a bit specialised: they can't hold primitive types such as Byte, nor nullable types such as String?, and have to be var even if the value never changes once set. They also have a small performance overhead (having to check for initialisation at each access) — and of course if you make a coding error you get an UninitializedPropertyAccessException at some point during runtime instead of a nice compile-time error. lateinit is very useful for a few specific cases, such as dependency injection, but I wouldn't recommend them for anything else.


(* In fact, there are rare corner cases that let you see a property before it's been properly initialised, involving constructors calling overridden methods or properties. (In Kotlin/JVM, you get to see Java's 0/false/null; I don't know about other platforms.) This is why it's usually recommended not to call any of a class's non-final methods or properties from its constructors or init blocks.)

Upvotes: 0

Ivo
Ivo

Reputation: 23164

What W3Schools fails to mention is that it only holds true for variables that are not top level. So inside functions like

fun someFunction() {
    var byteEg: Byte
}

if you want to do it with top level declarations you can mark it as lateinit like

lateinit var byteEg: Byte

Upvotes: 1

Related Questions