Property initialization using "by lazy" vs. "lateinit" - properties

In Kotlin, if you don't want to initialize a class property inside the constructor or in the top of the class body, you have basically these two options (from the language reference):
Lazy Initialization
lazy() is a function that takes a lambda and returns an instance of Lazy<T> which can serve as a delegate for implementing a lazy property: the first call to get() executes the lambda passed to lazy() and remembers the result, subsequent calls to get() simply return the remembered result.
Example
public class Hello {
val myLazyString: String by lazy { "Hello" }
}
So, the first call and the subsequential calls, wherever it is, to myLazyString will return Hello
Late Initialization
Normally, properties declared as having a non-null type must be initialized in the constructor. However, fairly often this is not convenient. For example, properties can be initialized through dependency injection, or in the setup method of a unit test. In this case, you cannot supply a non-null initializer in the constructor, but you still want to avoid null checks when referencing the property inside the body of a class.
To handle this case, you can mark the property with the lateinit modifier:
public class MyTest {
lateinit var subject: TestSubject
#SetUp fun setup() { subject = TestSubject() }
#Test fun test() { subject.method() }
}
The modifier can only be used on var properties declared inside the body of a class (not in the primary constructor), and only when the property does not have a custom getter or setter. The type of the property must be non-null, and it must not be a primitive type.
So, how to choose correctly between these two options, since both of them can solve the same problem?

Here are the significant differences between lateinit var and by lazy { ... } delegated property:
lazy { ... } delegate can only be used for val properties, whereas lateinit can only be applied to vars, because it can't be compiled to a final field, thus no immutability can be guaranteed;
lateinit var has a backing field which stores the value, and by lazy { ... } creates a delegate object in which the value is stored once calculated, stores the reference to the delegate instance in the class object and generates the getter for the property that works with the delegate instance. So if you need the backing field present in the class, use lateinit;
In addition to vals, lateinit cannot be used for nullable properties or Java primitive types (this is because of null used for uninitialized value);
lateinit var can be initialized from anywhere the object is seen from, e.g. from inside a framework code, and multiple initialization scenarios are possible for different objects of a single class. by lazy { ... }, in turn, defines the only initializer for the property, which can be altered only by overriding the property in a subclass. If you want your property to be initialized from outside in a way probably unknown beforehand, use lateinit.
Initialization by lazy { ... } is thread-safe by default and guarantees that the initializer is invoked at most once (but this can be altered by using another lazy overload). In the case of lateinit var, it's up to the user's code to initialize the property correctly in multi-threaded environments.
A Lazy instance can be saved, passed around and even used for multiple properties. On contrary, lateinit vars do not store any additional runtime state (only null in the field for uninitialized value).
If you hold a reference to an instance of Lazy, isInitialized() allows you to check whether it has already been initialized (and you can obtain such instance with reflection from a delegated property). To check whether a lateinit property has been initialized, you can use property::isInitialized since Kotlin 1.2.
A lambda passed to by lazy { ... } may capture references from the context where it is used into its closure.. It will then store the references and release them only once the property has been initialized. This may lead to object hierarchies, such as Android activities, not being released for too long (or ever, if the property remains accessible and is never accessed), so you should be careful about what you use inside the initializer lambda.
Also, there's another way not mentioned in the question: Delegates.notNull(), which is suitable for deferred initialization of non-null properties, including those of Java primitive types.

lateinit vs lazy
lateinit
i) Use it with mutable variable[var]
lateinit var name: String //Allowed
lateinit val name: String //Not Allowed
ii) Allowed with only non-nullable data types
lateinit var name: String //Allowed
lateinit var name: String? //Not Allowed
iii) It is a promise to compiler that the value will be initialized in future.
NOTE: If you try to access lateinit variable without initializing it then it throws UnInitializedPropertyAccessException.
lazy
i) Lazy initialization was designed to prevent unnecessary initialization of objects.
ii) Your property will not be initialized unless you use it.
iii) It is initialized only once. Next time when you use it, you get the value from cache memory.
iv) It is thread safe(It is initialized in the thread where it is used for the first time. Other threads use the same value stored in the cache).
v) The property can only be val.
vi) The property can be of any type (including primitives and nullables, which are not allowed with lateinit).

Very Short and concise Answer
lateinit: It initialize non-null properties lately
Unlike lazy initialization, lateinit allows the compiler to recognize that the value of the non-null property is not stored in the constructor stage to compile normally.
lazy Initialization
by lazy may be very useful when implementing read-only(val) properties that perform lazy-initialization in Kotlin.
by lazy { ... } performs its initializer where the defined property is first used, not its declaration.

Additionnally to hotkey's good answer, here is how I choose among the two in practice:
lateinit is for external initialisation: when you need external stuff to initialise your value by calling a method.
e.g. by calling:
private lateinit var value: MyClass
fun init(externalProperties: Any) {
value = somethingThatDependsOn(externalProperties)
}
While lazy is when it only uses dependencies internal to your object.

In addition to all of the great answers, there is a concept called lazy loading:
Lazy loading is a design pattern commonly used in computer programming to defer initialization of an object until the point at which it is needed.
Using it properly, you can reduce the loading time of your application. And Kotlin way of it's implementation is by lazy() which loads the needed value to your variable whenever it's needed.
But lateinit is used when you are sure a variable won't be null or empty and will be initialized before you use it -e.g. in onResume() method for android- and so you don't want to declare it as a nullable type.

Everything is correct above, but one of facts simple explanation LAZY----There are cases when you want to delay the creation of an instance of your object until its
first usage. This technique is known as lazy initialization or lazy instantiation. The main
purpose of lazy initialization is to boost performance and reduce your memory footprint. If
instantiating an instance of your type carries a large computational cost and the program
might end up not actually using it, you would want to delay or even avoid wasting CPU
cycles.

Diff btw lateinit and lazy
lateinit
Use only with mutable variable i.e. var and non-nullable data types
lateinit var name: String //Allowed with non-nullable
You are telling the compiler that the value will be initialized in future.
NOTE: If you try to access lateinit variable without initializing it then it throws UnInitializedPropertyAccessException.
lazy
Lazy initialization was designed to prevent unnecessary initialization of objects.
Your variable will not be initialized unless you use it.
It is initialized only once. Next time when you use it, you get the value from cache memory.
It is thread safe.
The variable can only be val and non-nullable.
Cheers :)

If you are using Spring container and you want to initialize non-nullable bean field, lateinit is better suited.
#Autowired
lateinit var myBean: MyBean

If you use an unchangable variable, then it is better to initialize with by lazy { ... } or val. In this case you can be sure that it will always be initialized when needed and at most 1 time.
If you want a non-null variable, that can change it's value, use lateinit var. In Android development you can later initialize it in such events like onCreate, onResume. Be aware, that if you call REST request and access this variable, it may lead to an exception UninitializedPropertyAccessException: lateinit property yourVariable has not been initialized, because the request can execute faster than that variable could initialize.

Related

How does kotlin compiler know whether a val should be a property or a function

The following kotlin code
val nameHash get() = name.hashCode()
can be compiled into java as follows
public final int getNameHash() {
return name.hashCode();
}
and the property nameHash disapears.
However when the val is changed to var, the compiler says "Property must be initialized"
What is the deeper difference between var and val?
How does kotlin compiler know whether a val should be a property or a function
As far as the Kotlin language is concerned, val denotes properties, never functions. However, there is a difference between these two property declarations:
val nameHash get() = name.hashCode()
var nameHash get() = name.hashCode()
And that is that the first property does not have a backing field. Properties with backing fields must be initialised one way or another, for example:
var nameHash = 0 // for example
get() = name.hashCode()
And this is why your code with var didn't compile.
If you are asking for the situations when a backing field is generated for a Kotlin property, they are listed in the spec:
However, the backing field is created for a property only in the
following cases
A property has no custom accessors;
A property has a default accessor;
A property has a custom accessor, and it uses field property;
A mutable property has a custom getter or setter, but not both.
These are the cases where your property needs a backing field. Your var nameHash satisfies that last case, because it is a "mutable property". If you use val instead, it is not a mutable property anymore and doesn't satisfy any of those cases.
Intuitively, a mutable property without setter needs a backing field because one must need to be able to set the property. How can you set it when it has no setter? Well, the Kotlin compiler solves the problem by generating a backing field and just sets the backing field instead.
Property is a functions set() & get(). Read-only properties implement only the get() function, but still, it's a function, so everything written in the property will be executed every time it's called.
In Kotlin, keywords: val is the same as the read-only property, meaning it's required to implement only get() function. When you put var keyword, compiler expects you to implement both get() & set() functions.
So, compile error there because your property missing set() function that is usually needed to store a value (or as the compiler says: must be initialized).
The error message is a little confusing in this case. The difference between val and var is that val means there is a getter while var means there is a getter and a setter. To fix your code you need to add an implementation for the setter:
var nameHash
get() = name.hashCode()
set(hash: Int) { ... }
Although, in this case I don't think it makes too much sense. We can't set the hash code value of the name.

Understanding the impact of var and val with respect to getters and setters of a property

Let's say I have a Kotlin class Dog with two properties weight and weightInKgs
class Dog(val weight: Double) {
// property without initializing works. Why?
val weightinKgs: Double
get() = weight/ 2.2;
}
The above code runs without errors. I know that every property in Kotlin must be initialized so why does defining a getter without initializing the property work? Secondly, when val is changed to var for weightInKgs, it produces an error asking for initialization. How does changing it to var break the code?
class Dog(val weight: Double) {
// well its doesn't work now.
var weightinKgs: Double
get() = weight/ 2.2;
}
Every property with a backing field must be initialized. A property has a backing field if any of the following is true:
You initialize the backing field at the declaration site using =.
It has a custom getter or setter that references field.
It uses the implicit getter or setter, which implicitly uses field.
Otherwise, it does not have a backing field.
If there is no backing field used by the getter and/or setter, there is no need to initialize one. Your first code block has a custom getter that doesn't use field.
In your second code block, you have a var and it's using the implicit setter, which uses the backing field, so the backing field must be initialized.
If it's not obvious, get() is a function that calculates a value (weight / 2.2) every time you call it. It's basically the equivalent to this
fun getWeightInKgs(): Double {
return weight / 2.2
}
So that's why it doesn't have a backing field, it's not actually storing a value. But Kotlin presents these kinds of getX() functions (and set, is etc) as properties, and encourages you to use property access syntax, so dog.weightInKgs instead of dog.getWeightInKgs(). Kinda hiding the specific implementation details
If you didn't want to calculate the weight every time, and just wanted to do it once, then you'd just do
val weightInKgs = weight / 2.2
and then it would have a backing field, because that value has to be stored somewhere. You could also have a getter function that refers to a private val or var and returns the value of that, instead of giving the property itself a backing field, but if you ever need to do that kind of thing you'll probably understand why you would! That's usually for when your getter and/or setter is doing something a bit more complicated than just hiding or validating an internal data value

How to test if lateinit var is initialized from outside the class? - Kotlin

This SO post outlines how to test if a lateinit var has been initialized. However, in the example, the lateinit var is conveniently located within the same class.
How do you do the same thing from outside the class? This is the situation I have:
Foo.kt
class Foo {
lateinit var foo: String
}
Bar.kt
class Bar {
fun doSomething() {
val foo = Foo().foo
if (::foo.isInitialized) { // Unsupported [reference to variables aren't supported yet]
Log.i("TAG", "do something")
}
}
}
What's the workaround for this?
If this was going to work, you'd need to do
val foo = Foo()
if (foo::foo.isInitialized)
//...
The way you're doing it, you're trying to get a property reference of your local variable, which isn't a property. That's why the error says "reference to variables aren't supported yet" rather than "backing field not accessible at this point". Also, you'd be accessing the getter of the lateinit property when assigning the local variable, so it would fail if it weren't initialized yet.
But it doesn't work because of compiler limitations. You could simply add a getter
val fooReady: Boolean get() = ::foo.isInitialized
But I would say the design has very poor encapsulation if outside classes need to check whether a particular public property is initialized yet. In my opinion, any use of isInitialized is a code smell to begin with. If you need to guard calls to the getter with isInitialized, you might as well make the property nullable instead. Then you can use the familiar idioms of null checks instead of resorting to reflection, and it will work in a familiar way even for external classes that access it.
If object of another class has to make a decision based on whether or not the property is initialised, then having this property initialised - or answering whether or not it has already been initialised - is a public business capacity of your object and therefore I would recommend you to simply make it a part of your public API via public fun isFooInitialised(): Boolean function that utilises the fact that the object itself can inspect the state of its lateinit properties.

What does get() do when assigning value in Kotlin?

The code here is assigning the _showProgress to showProgress by using the get()
private val _showProgress = MutableLiveData<SingleLiveEventWrapper<Boolean>>()
override val showProgress : LiveData<SingleLiveEventWrapper<Boolean>>
get() = _showProgress
The code here is the same as above and it seems like there is no difference when running the code, it does the same job as above. What does the get() in the above code do? Is it necessary to use the get() when assigning the value?
private val _showProgress = MutableLiveData<SingleLiveEventWrapper<Boolean>>()
override val showProgress : LiveData<SingleLiveEventWrapper<Boolean>> = _showProgress
The get() method doesn't change the value — but it does change the type. (The static, compile-time type, anyway.)
The private property is a MutableLiveData field. I don't know that type, but it looks like a class or interface which wraps some data (in this case a SingleLiveEventWrapper<Boolean>), and allows it to be changed.
The public property, though, is a LiveData. That's probably a superclass or superinterface of MutableLiveData which lacks the method(s) allowing the data to be changed. The overridden getter method simply returns the value of the private property, but in doing so upcasts it to the non-mutable type.
The result is that code within the class can access the mutable field, which other code can only get a read-only view of it. So it's effectively doing some encapsulation, restricting the ability to change the field while still allowing it to be seen.
(You wouldn't need to call the getter explicitly; simply using the property syntax myObject.showProgress will call the getter for you. In Kotlin, all properties get a getter method -- and, if var a setter; you only need to override the default ones if you want different behaviour.)
Adding a bit to gidds' answer and focusing specifically on comparison with
override val showProgress : LiveData<SingleLiveEventWrapper<Boolean>> = _showProgress
If you use = ... without an explicit getter, a backing field is created and _showProgress is stored there while constructing the object. So there are two fields storing the same value. In this case this shouldn't make any difference beyond using a bit more memory, but in other cases it could:
if _showProgress was a var it could be reassigned after construction. Then if showProgress is defined with get(), accessing it will always get the current value of _showProgress, but without get() it'll get the initial one.
Similarly if _showProgress was open protected and overridden in a subclass (due to initialization order).

Variables not initialized properly when initializing it in an overriden abstract function called from constructor or init block

I hit a problem with some Kotlin code and I found out it was related to calling a method that assigns some variables from an init block (or a secondary constructor for that matter, either reproduces the problem).
MCVE:
abstract class Shader(/*Input arguments omitted for the sake of an MCVE*/){
init{
//Shader loading and attaching, not relevant
bindAttribs()//One of the abstract methods. In my actual program, this uses OpenGL to bind attributes
//GLSL program validation
getUniforms()//Same as the previous one: abstract method using GL calls to get uniforms. This gets locations so an integer is set (the problem)
}
abstract fun getUniforms();//This is the one causing problems
abstract fun bindAttribs();//This would to if primitives or non-lateinit vars are set
}
abstract class BoilerplateShader() : Shader(){
var loc_projectionMatrix: Int = 404//404 is an initial value. This can be anything though
var loc_transformationMatrix: Int = 404
var loc_viewMatrix: Int = 404
override fun getUniforms(){
//These would be grabbed by using glGetUniformLocations, but it's reproducable with static values as well
loc_projectionMatrix = 0
loc_transformationMatrix = 1
loc_viewMatrix = 2
println(loc_projectionMatrix.toString() + ", " + loc_transformationMatrix + ", " + loc_viewMatrix)
}
//debug method, only used to show the values
fun dump(){
println(loc_projectionMatrix.toString() + ", " + loc_transformationMatrix + ", " + loc_viewMatrix)
}
}
class TextureShader() : BoilerplateShader(){
override fun bindAttribs() {
//This doesn't cause a problem even though it's called from the init block, as nothing is assigned
//bindAttrib(0, "a_position");
//bindAttrib(1, "a_texCoord0");
}
}
//Other repetitive shaders, omitted for brevity
Then doing:
val tx = TextureShader()
tx.dump()
prints:
0, 1, 2
404, 404, 404
The print statements are called in order from getUniforms to the dump call at the end. It's assigned fine in the getUniforms method, but when calling them just a few milliseconds later, they're suddenly set to the default value of (in this case) 404. This value can be anything though, but I use 404 because that's a value I know I won't use for testing in this particular MCVE.
I'm using a system that relies heavily on abstract classes, but calling some of these methods (getUniforms is extremely important) is a must. If I add an init block in either BoilerplateShader or TextureShader with a call to getUniforms, it works fine. Doing a workaround with an init function (not an init block) called after object creation:
fun init(){
bindAttribs();
getUniforms();
}
works fine. But that would involve the created instance manually calls it:
val ts = TexturedShader();
ts.init();
ts.dump()
which isn't an option. Writing the code that causes problems in Kotlin in Java works like expected (considerably shortened code, but still reproducable):
abstract class Shader{
public Shader(){
getUniforms();
}
public abstract void getUniforms();
}
abstract class BoilerplateShader extends Shader{
int loc_projectionMatrix;//When this is initialized, it produces the same issue as Kotlin. But Java doesn't require the vars to be initialized when they're declared globally, so it doesn't cause a problem
public void getUniforms(){
loc_projectionMatrix = 1;
System.out.println(loc_projectionMatrix);
}
//and a dump method or any kind of basic print statement to print it after object creation
}
class TextureShader extends BoilerplateShader {
public TextureShader(){
super();
}
}
and printing the value of the variable after initialization of both the variable and the class prints 0, as expected.
Trying to reproduce the same thing with an object produces the same result as with numbers when the var isn't lateinit. So this:
var test: String = ""
prints:
0, 1, 2, test
404, 404, 404,
The last line is exactly as printed: the value if test is set to an empty String by default, so it shows up as empty.
But if the var is declared as a lateinit var:
lateinit var test: String
it prints:
0, 1, 2, test
404, 404, 404, test
I can't declare primitives with lateinit. And since it's called outside a constructor, it either needs to be initialized or be declared as lateinit.
So, is it possible to initialize primitives from an overridden abstract method without creating a function to call it?
Edit:
A comment suggested a factory method, but that's not going to work because of the abstraction. Since the attempted goal is to call the methods from the base class (Shader), and since abstract classes can't be initialized, factory methods won't work without creating a manual implementation in each class, which is overkill. And if the constructor is private to get it to work (avoid initialization outside factory methods), extending won't work (<init> is private in Shader).
So the constructors are forced to be public (whether the Shader class has a primary or secondary constructor, the child classes have to have a primary to initialize it) meaning the shaders can be created while bypassing the factory method. And, abstraction causes problems again, the factory method (having to be abstract) would be manually implemented in each child class, once again resulting in initialization and manually calling the init() method.
The question is still whether or not it's possible to make sure the non-lateinit and primitives are initialized when calling an abstract method from the constructor. Creating factory methods would be a perfect solution had there not been abstraction involved.
Note: The absolutely best idea is to avoid declaring objects/primitives in abstract functions called from the abstract class' constructor method, but there are cases where it's useful. Avoid it if possible.
The only workaround I found for this is using by lazy, since there are primitives involved and I can convert assignment to work in the blocks.
lateinit would have made it slightly easier, so creating object wrappers could of course be an option, but using by lazy works in my case.
Anyways, what's happening here is that the value assigned to the int in the constructor is later overridden by the fixed value. Pseudocode:
var x /* = 0 */
constructor() : super.constructor()//x is not initialized yet
super.constructor(){
overridden function();
}
abstract function()
overridden function() {
x = 4;
}
// The assignment if `= 0` takes place after the construction of the parent, setting x to 0 and overriding the value in the constructor
With lateinit, the problem is removed:
lateinit var x: Integer//x exists, but doesn't get a value. It's assigned later
constructor() : super.constructor()
super.constructor(){
overridden function()
}
abstract function()
overridden function(){
x = Integer(4);//using an object here since Kotlin doesn't support lateinit with primtives
}
//x, being lateinit and now initialized, doesn't get re-initialized by the declaration. x = 4 instead of 0, as in the first example
When I wrote the question, I thought Java worked differently. This was because I didn't initialize the variables there either (effectively, making them lateinit). When the class then is fully initialized, int x; doesn't get assigned a value. If it was declared as int x = 1234;, the same problem in Java occurs as here.
Now, the problem goes back to lateinit and primitives; primitives cannot be lateinit. A fairly basic solution is using a data class:
data class IntWrapper(var value: Int)
Since the value of data classes can be unpacked:
var (value) = intWrapperInstance//doing "var value = ..." sets value to the intWrapperInstance. With the parenthesis it works the same way as unpacking the values of a pair or triple, just with a single value.
Now, since there's an instance with an object (not a primitive), lateinit can be used. However, this isn't particularly efficient since it involves another object being created.
The only remaining option: by lazy.
Wherever it's possible to create initialization as a function, this is the best option. The code in the question was a simplified version of OpenGL shaders (more specifically, the locations for uniforms). Meaning this particular code is fairly easy to convert to a by lazy block:
val projectionMatrixLocation by lazy{
glGetUniformLocation(program, "projectionMatrix")
}
Depending on the case though, this might not be feasible. Especially since by lazy requires a val, which means it isn't possible to change it afterwards. This depends on the usage though, since it isn't a problem if it isn't going to change.