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

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.

Related

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).

In Kotlin what does this get() do

Im new to Kotlin and wonder what does the get() = login_email.txt.toString() do?
Does it set email String?
get() and set(value) after a field means the declaration of a custom getter and/or setter. Here's a basic example using default values:
class Demo{
var something: String
get() = field
set(value) {
field = value;
}
constructor(something: String){
this.something = something;
}
}
These two are, however, redundant. You don't actually need them unless you're doing something custom with it. They're automatically added for vars, though that only applies to getters for vals (because they can't be changed, they don't have setters).
The line you were asking about is a custom getter.
get() // declares a custom getter
= // if you don't know how this works, see my explanation below
login_email.text.toString() // you should be familiar with this part already; gets the string value of the field
If you're not familiar with the syntax, this is the equivalent without =:
get(){
return login_email.text.toString()
}
if you have a single return, you can replace the brackets and return keyword with =. If it helps you remember, just remember the alternative to using = (a body + the return keyword)
TL;DR: it declares a custom setter that returns the value of a TextView/EditText (not sure which it is, you didn't include that in the question)
In your case, you're using a custom getter or setter to handle property data. The fields themselves don't actually contain any data, but you have getters for a different object.
Take this as an example:
class Demo(private val someObject: MyCustomObjectWithSomeData){
val text: String
get() = someObject.text
... same for other stuff. Could also have setters, if the properties are mutable
}
Here the object is private, but it could be public or internal for that matter.
Kotlin supports quite a lot with custom getters. For an instance, you can declare a field to display specific fields of a private variable. For an instance, in your case, you have the email. It doesn't need to be a variable, since you have a custom getter, and the field isn't initialized. If you change var email to a val, you can make it non-null:
val email: String
get() = login_email.text.toString()
That also helps with null-safety.
And for the error field, it's slightly more complicated. It can't be a val because you declare a custom setter, but if you add a getter, you can make it non-null:
var error: String
get() = login_error.text.toString()
set(value){
login_error.text = value;
}
Short Answer
get() is used to define a custom getter method. Anytime you access the property you are using the custom getter method
Long Answer
So before we can talk about get(), it is important that we get a proper understanding of what properties actually are.
Properties
We all know that in object oriented programming the main idea of a class is to encapsulate data and code that works on data in a single class. In a language like Java (don't worry we will get back to Kotlin soon), the data of a class is stored in private fields, we then use accessor method (getters and setters) to access the data. In Java the combination of accessor methods and a field is called a property
Now in Kotlin does things a little differently, it entirely replaces the traditional idea of defining accessor methods and fields. By using the val or var keyword Kotlin will automatically generate the corresponding field and appropriate accessor methods for us.
get()
There will come a time when either your code or someone else's code needs a more robust solution to the automatic accessor methods created by Kotlin. This is where get() and set() come into play. By using get() you are defining your own custom accessor method(getter for get()) to be used when you are accessing this property.
I would also like to point out that since val is immutable it does not allow you to define a set() method, only a get()

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

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.