By changing the contract I actually meant two things. First is a technical/bytecode change: it would mean that the type of the property differs between constructor, field, getter and setter. Right now I believe (?) it is always the same, so tools using reflection, annotation processors, etc. may work improperly.
Second difference is behavioral. Right now you can assume whatever you set to a property of a data class, will be stored there as is. These props are simple data holders, getting or setting them is not associated with any additional behavior or side-effects. In this respect they are similar to local variables. Normally, you assume you have full control over local variables and you don’t expect they store a different value that you just set them to (still, this is possible with property delegates).
Having said that, I’m not a part of the Kotlin team and I’m not authorized to say how data classes should or shouldn’t work. This is just my understanding of these classes.
Regarding non-data classes, I don’t see why not to use such feature. Normal classes don’t have any kind of contract. Unfortunately, I believe it is not possible to automatically generate equals()
and other methods for non-data classes.
And I don’t really see how this is a Java interop thing. In both Java and Kotlin we sometimes substitute nulls with default values. In both Java and Kotlin it is generally discouraged to solve the problem of a function with large number of optional params by making them nullable. In both of these languages nulls are considered just one of possible values and not the lack of a value. If you pass a null in varargs, it won’t be skipped, but passed as null. If you set a HashMap
item to a null, it won’t become unset, but set to null. new StringBuilder(null)
is not considered the same as new StringBuilder()
- it throws NPE. And so on. For sure there are some stdlib APIs that treat nulls similar to missing params, but I don’t think this is a common way of doing things in Java/Kotlin.