Improving lateinit


#1

I have 2 suggestions how lateinit could be improved.

First: lateinit can’t be val. It’s OK for class with something like onCreate method, where the field must be initialized from the Kotlin method. But there are many environments, where fields are initialized using reflection, like Spring DI or JavaEE DI. lateinit var looks strange. I don’t want to change those values from Kotlin code, but language doesn’t help me to show that intent. IMO it should be possible to use lateinit val to express the intent that this field must be initialized by reflection. I don’t really see any problems with that.

Second: there are some restrictions: lateinit can’t be used with the primitive and nullable types. I’ll describe my usecase: I use lateinit-like mechanism for my data classes. I load some fields from the DB and then I use those fields. I don’t necessarily want to load every field from DB, sometimes I only need few of them. But on the other hand, if i made a mistake and I’m trying to use a non-initialized value, I want to have an exception. So lateinit would be a perfect match for that use-case, but my fields can be nullable or primitive. So I have to distinguish between null and uninitialized value. I implemented it using Map<KProperty, Any?> and delegate properties, but native support would be better, both from performance reasons and from usability reasons.

For nullable and primitive types compiler could generate a bitset field (1 long field enough for 64 nullable fields). Getter method would check proper bit and setter method would set proper bit. It would be much more efficient than a Map<KProperty, Any?>.

Also some method, probably somewhere in the reflection package, to check whether field was initialized, would be helpful too. Of course I can just get the value and catch an exception, but exception throw/catch is quite slow, compared with simple comparison.

Now the only tricky case is using lateinit val with nullable or primitive types. Reflection will write the value to the field directly, so it’s not possible to detect initialization, at least if the value was initialized using null or 0/false/etc. Probably that particular combination should be forbidden.


#2

Use property delegates from stdlib, for example ‘x by Delegates.NotNull()’


#3

I’ll add my vote as well for lateinit val for non-nullable types!


#4

The bitset field approach has its issues when it comes to atomicity of assignment: a volatile var of such structure might not actually work as expected.

The problem with val is that Java clients can still mutate the corresponding field directly, which breaks the intuition of vals being final in the Java sense


#5

Sorry if I resume an old thread, but can you confirm that I really can’t make the following class a data class?

class Shipwreck {
    var id: Long by Delegates.notNull()
    var name: String by Delegates.notNull()
    var description: String? = null
    var condition: String? = null
    var depth: Int? = null
    var latitude: Double? = null
    var longitude: Double? = null
    var yearDiscovered: Int? = null

    constructor()
    
    constructor(id: Long,
                name: String,
                description: String? = null,
                condition: String? = null,
                depth: Int? = null,
                latitude: Double? = null,
                longitude: Double? = null,
                yearDiscovered: Int? = null) {
        this.id = id
        this.name = name
        this.description = description
        this.condition = condition
        this.depth = depth
        this.latitude = latitude
        this.longitude = longitude
        this.yearDiscovered = yearDiscovered
    }
}

basically I need a default empty constructor for serialization/deserialization, but at the same time I want to enforce non-nullability on the id and name properties…

PS: at least, is there a more idiomatic (read concise) way to write constructors like the above, beside primary constructors?

Thanks!


#6

We are working on support for serialization in the cases like yours