Do we need to initialize nullable fields in kotlin? - kotlin

I have recently reviewed some kotlin codes, All nullable field initialized as null.
What is the difference between val x : String? = null and val x : String?
Should we initialize the nullable fields as null?

Everything, even nullable variables and primitives, need to be initialized in Kotlin. You can, as tynn mentioned, mark them as abstract if you require overriding. If you have an interface, however, you don't have to initialize them. This won't compile:
class Whatever {
private var x: String?
}
but this will:
interface IWhatever {
protected var x: String?
}
This too:
abstract class Whatever {
protected abstract var x: String?
}
If it's declared in a method, you don't have to initialize it directly, as long as it's initialized before it's accessed. This is the exactly same as in Java, if you're familiar with it.
If you don't initialize it in the constructor, you need to use lateinit. Or, if you have a val, you can override get:
val something: String?
get() = "Some fallback. This doesn't need initialization because the getter is overridden, but if you use a different field here, you naturally need to initialize that"
As I opened with, even nullable variables need to be initialized. This is the way Kotlin is designed, and there's no way around that. So yes, you need to explicitly initialize the String as null, if you don't initialize it with something else right away.

A property must be initialized. Therefore you have to do the initialization var x : String? = null. Not assigning a value is only the declaration of the property and thus you'd have to make it abstract abstract val x : String?.
Alternatively you can use lateinit, also on non-nullable types. But this has the effect, that it's not null, but uninitialized lateinit var x : String.

val x : String? will create an uninitialized variable or property, depending on where it's defined. If it's in a class (rather than a function), it creates a property, and you cannot create an uninitalized property unless it's abstract. For example take this code:
class MyClass {
val x : String?
}
This won't compile. You'll get Property must be initialized or be abstract.
This code, however, will compile
class MyClass {
fun test() {
val x : String?
}
}
However it's a bit pointless as you will not be able to refer to that variable: as soon as you do you'll get Variable 'x' must be initialized.
So yes, generally when defining a nullable member you should initialize it (e.g. with a value of null), unless it's abstract, in which case the overriding class should initialize it.

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.

Access Implementation's property on variable of type Interface

I'm trying to access the delegate of the property (id) of a class (FooImpl). The problem is, this class implements an interface (Foo), and the property in question overrides a property of this interface. The delegate only exists in the class (not that it could exist in the interface).
The problem is that using the :: operator on a variable of type Foo always returns the property of Foo, not that of the actual instance. The problem in code:
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty0
import kotlin.reflect.jvm.isAccessible
interface Foo {
val id: Int
}
class FooImpl(
id: Int,
) : Foo {
override val id: Int by lazy { id }
}
val <T> KProperty<T>.hasDelegate: Boolean
get() = apply { isAccessible = true }.let { (it as KProperty0<T>).getDelegate() != null }
fun main() {
val foo: Foo = FooImpl(1)
println("foo::id.hasDelegate = ${foo::id.hasDelegate}")
println("(foo as FooImpl)::id.hasDelegate = ${(foo as FooImpl)::id.hasDelegate}")
}
This prints:
foo::id.hasDelegate = false
(foo as FooImpl)::id.hasDelegate = true
But this requires compile-time knowledge of the correct implementation. What I'm looking for is accessing the correct propert without having to specify FooImpl there.
The information is present at runtime because the least (!) intrusive workaround I have found so far is adding fun idProp(): KProperty0<*> to Foo and override fun idProp() = ::id to FooImpl and accessing the property using that.
Is there any better way than that?
I came up with this, but I don't know if there's a better way. The problem to work around is that getDelegate() has to return an actual instance of the delegate, so you need an instance of the class to be able to retrieve a delegate instance. It would really be nice if there was a hasDelegate property built in. Your version of hasDelegate will crash from the cast on unbound KProperty1's, which is all we have to work with when the specific class is unknown.
So to retrieve the delegate instance, we need to do search the class instance's member properties by name, which gives us a KProperty with covariant class type of the super-class type. Since it's covariant, we can call a consuming function like getDelegate() without casting to the invariant type. I think this logically should be safe, since we are passing an instance that we know has the matching type for the ::class that we retrieved the property with.
#Suppress("UNCHECKED_CAST")
fun <T: Any> KProperty1<T, *>.isDelegated(instance: T): Boolean =
(instance::class.memberProperties.first { it.name == name } as KProperty1<T, *>).run {
isAccessible = true
getDelegate(instance) != null
}
fun main() {
val foo: Foo = Foo2()
println("foo::id.hasDelegate = ${Foo::id.isDelegated(foo)}")
}
The problem here is that the owner of the property is resolved on compile time, not on runtime. When you do foo::id then foo (so FooImpl) become its bound receiver, but owner is still resolved to Foo. To fix this we wound need to "cast" property to another owner. Unfortunately, I didn't find a straightforward way to do this.
One solution I found is to use foo::class instead of foo::id as it resolves KClass on runtime, not on compile time. Then I came up with almost exactly the same code as #Tenfour04.
But if you don't mind using Kotlin internals that are public and not protected with any annotation, you can use much cleaner solution:
val KProperty0<*>.hasDelegate: Boolean
get() = apply { isAccessible = true }.getDelegate() != null
fun KProperty0<*>.castToRuntimeType(): KProperty0<*> {
require(this is PropertyReference0)
return PropertyReference0Impl(boundReceiver, boundReceiver::class.java, name, signature, 0)
}
fun main() {
val foo: Foo = FooImpl(1)
println(foo::id.castToRuntimeType().hasDelegate) // true
}
We basically create a new instance of KProperty, copying all its data, but changing the owner to the same type as its bound receiver. As a result, we "cast" it to the runtime type. This is much simpler and it is also cleaner because we separated property casting and checking for a delegate.
Unfortunately, I think Kotlin reflection API is still missing a lot of features. There should be hasDelegate() function, so we don't have to provide receivers, which is not really needed to check if property is delegated. It should be possible to cast KProperty to another type. It should be possible to create bound properties with some API call. But first of all, it should be possible to do something like: Foo::id(foo), so create KProperty of the runtime type of foo. And so on.

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.

Kotlin, set var/val once to make it final, is that possible

In Kotlin, we have val that is final and can't be change. e.g.
val something = "Something"
If a value that is is initialized later, we use lateinit var.
lateinit var something: String
But this is var instead of val. I wanted to set something once (not in constructor), and have it as final. How could I achieve this?
Reading into the conventions of Kotlin, a late-initialized variable which is final is impossible.
Consider its use case:
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.
lateinit var is providing relative sanity when dealing with a variable that may not have yet been initialized, such as the case with injected fields (like Spring and #Autowired). Then, speaking strictly in the context of dependency injection, if you don't have a way to concretely instantiate the variable at compile time, then you cannot leave it as a final field.
From a Java to Kotlin world, having a late initialized variable come in as final would look as paradoxical as this from Spring:
#Autowired
private final Interface something;
What do you think the behavior should be when you attempt to set it again? Do you expect this to be enforced at compile time? Should it cause a crash at runtime or just do nothing?
If you expect it to happen at compile time, I'm pretty sure it's not possible for a compiler to catch something like that.
If you want some other behavior, you can make it a private variable with a public set method that does whatever you want if it's been already set.
Or you could encapsulate it in an instance of a custom class that does whatever behavior you want.
You can use following delegate class:
import kotlin.reflect.KProperty
class WriteOnce<T> {
private var holder = holdValue<T>()
private var value by holder
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
if (!holder.hasValue) {
throw IllegalStateException("Property must be initialized before use")
}
return value
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
if (holder.hasValue) {
throw RuntimeException("Write-once property already has a value")
}
this.value = value
}
}
fun <T> holdValue() = ValueHolder<T>()
class ValueHolder<T> {
var value: T? = null
var hasValue: Boolean = false
private set
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
hasValue = true
}
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return this.value!!
}
}
Usage:
var example by WriteOnce<String>()
If you try to write a to the variable a second time it will produce a RuntimeException:
java.lang.RuntimeException: Write-once property already has a value
Not having any value also produces an exception, similar to as if you were using lateinit:
java.lang.IllegalStateException: Property must be initialized before use
Which means this is val and lateinit combined because you can set the value at any time, only once ever.
The downside to this implementation is that this is not checked at compile time, meaning that you will only ever see errors in runtime. If that's acceptable in your use case, it certainly would be a good solution for what you're looking for.
For me this is more of a way to make sure that a variable is only every assigned once by code I control – something I can catch during testing as well as in production as a way to improve security by preventing foreign code from changing a variable.
It is possible you can use You can create a custom delegate for the property that is a combination of the existing notNull delegate and your own idea of set once. Read more about property delegates for information on how to create a custom one that can do whatever you want, including the use case you want here. You would then not use lateinit but instead this delegate.

what is the recommended way for using the Kotlin double-bang for nullable class member

In kotlin if the variable is nullable the kotlin will ask for either using !! or check the null before using it.
In the case of having nullable class member, inside the class anywhere refereeing this member kotlin will warn for checking the nullable.
class ClassWithNullableMemebr {
Var nullableMember: OtherClass? = null;
constructor (obj: OtherClass) {
nullableMember = obj
}
fun foo() {
nullableMember!!.doSomething()
}
fun getTheOtherClassMember : OtherClass {
return nullableMember!!
}
}
If the nullableMember is guaranteed to initialized in constructor, how to avoid the use of !!.
In Java or other language they could check null once and throw if by design the member should never be null. Then inside the class the member will be just be referenced without worry.
Someone suggested do
if (nullableMember != null) {
nullableMember!!.doSomething()
}
This will still need the !! even after the check, and it makes the code looks not pretty.
For this case really using ?. is not much different than using !! since the nullableMember is assigned in the constructor, and the function return it can not avoid the !!.
I think if this nullableMember is guaranteed not null after instantiate the class the using !! shouldn't be considered to be bad coding style. And there is no other way to avoid it.
Does anyone have suggestion to avoid the use of '!!' in the case like this?
If you are sure that variable will have not-null value, you should define it as not-nullable.
After this, there are two ways to avoid compiler warning and in sight variable initialization:
Usage of lateinit modifier
lateinit var nullableMember: OtherClass
Please note if you try to access this variable before its initialization, exception will be thrown
Usage of notNull() delegate
var nullableMember: OtherClass by Delegates.notNull()
Differences between these two you can find here.
If there is a need to set the value of this variable to null somewhere in the code, I am afraid that you'll have to use !! because there is no nicer way of doing this.
If the nullableMember is guaranteed to initialized in constructor
In your case it isn't. It will be initialized if you call the secondary constructor, but you also have the primary, parameterless constructor which initializes it to null.
And if it is guaranteed to be initialized to non-null in the constructor, then as Oliver's comment says, it shouldn't be nullable! And it should be val if it's only set in the constructor (including secondary ones) or init blocks.
I.e. this class should be simplified to
class ClassWithNullableMemebr(val nullableMember: OtherClass) {
fun foo() {
nullableMember.doSomething()
}
}
If it is guaranteed to be initialized on the constructor, then it doesn't need to be nullable at all.
You can have:
class ClassWithMember(val member: OtherClass) {
fun foo() {
member.doSomething()
}
}