Reputation:
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
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
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 val
s as well as var
s, 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
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