"DataType" for only initial null value

For various reasons I work with classes which contain variables for objects which only can be null if not initialized.
I would like this as an option to declare.

class Hull {

        var nodeHullOptions: List<HullOption>? = null
        private set

}

I would suggest a third option: Do not allow to assign null again, maybe mark it with an additional exclamation mark:

class Hull {

        var nodeHullOptions: List<HullOption>?! = null
        private set

}

The compiler can then do all the same checks it would do if there was no ‘?’, for all assignments, whereas read operations would allow null value.

There is one area of interest for me:

val isBig = nodeHullOptions != null && nodeHullOptions.size > 100

Error: Smart cast to ‘List’ is impossible, because ‘nodeHullOptions’ is a mutable property that could have been changed by this time

I could use !! or a construct with ?.let {}, but not allowing null in further assignments could also reduce one more error constellation.

‘lateinit’ also does not work, because in some cases it never gets a value.

So, what do you think?

What do you mean here? I think lateinit is exactly for the case you described.

@broot No, it is not. It is by design that in some cases these variables will never be initialized.

Think of a tree where you store the var parent and the var list of childs. The top-node will never have a parent and thus never be initialized. This is checked by parent == null. The bottom nodes do not have childs, as such also always null.

The usecase for lateinit is just a split second after object initialization, e.g. for JavaFx variables or in Android where during runtime you expect the variables to be initialized, but not as a design feature.

lateinit only cares about that you don’t access the property before it has been initialized. It doesn’t matter if it’s a split second or five a minute.

Maybe you can use lateinit together with .isInitialized for your use case?

1 Like

Ok, now I understand your case. I think there are really two separate features involved here.

First is a possibility to have a getter and a setter with different types. I think this could be pretty useful, I remember some discussions here about such feature, but I don’t know if there are any plan for it.

Second feature is that the compiler understands the property could only change from A type to B type and can make guarantees needed for smart-casting. This is more complicated than it sounds, because we need to remember properties are not fields, they can have custom behavior, they can be overridden in subtypes, etc. However, Kotlin compiler already does this e.g. for val properties - we can smart cast only if there is no custom getters and property is not open. So your case should be doable.

One note: I don’t think it should be limited to nulls. We can generalize this case to setter using a subtype of the getter.

Have you look at delegated properties? For example, Lazy, NotNull, etc.

Delegated properties can help with runtime checks, but OP basically needs a setter for List and getter for List?. Ideally, with smart cast improvements. I believe for now the best we can get are two functions instead of a property.

1 Like