First off, very promising language! That being said, I am not sure about an aspect of the Properties Features. Properties allow the outside to access the internals in restricted way. In Kotlin, backing fields are implicit which is fine, but what bothers me is the access pattern: Why is internal code using (possibly) publicly exposed accessor methods to reach internal data?
When using the property as an identifier within the class, kotlin will call the getter method to access the data. It seems to me that the correct default here should be that code within the class (and subclasses) should reach the backing field directly (unless no backing field exists). With the current syntax, problems start arising when adding extra functionality into the getter or setter. This extra functionality is meant to target code accessing the object from the outside only, but now it suddently affects internal code as well.
Take this scenario for example:
open class Person(public open var names: MutableList<String>) {
public fun addName(name: String) {
names.add(name)
}
public fun doWhatever() {
// This is an internal modification
names = arrayListOf()
}
}
class User(names: MutableList<String>) : Person(names) {
public var externalModificationCount: Int = 0
private set
override var names: MutableList<String>
get() {
//clone defensively
return java.util.ArrayList(super.names)
}
set(value) {
// I want to restrict certain external modifications
if(value.isEmpty()) {
throw IllegalArgumentException()
}
super.names = value
// I want to increase count for external modifications
externalModificationCount++
}
}
fun main(args : Array<String>) {
val john = Person(arrayListOf(“John”))
john.addName(“Smith”)
john.doWhatever()
val peter = User(arrayListOf(“Peter”))
peter.addName(“Smith”) // FAIL: does not add the name because it added the name into the copied list
peter.doWhatever() // FAIL: overridden names checks for empty lists
// Assume there was no assert, we get to this point
print(peter.externalModificationCount) // FAIL: prints 2 instead of 1 because of doWhatever changing the names property through the setter
}
I would suggest that using the property identifier as a bare word (‘names’ here) from within the class and subclasses should access the backing field since that is what we mean to do most of the time. An alternative syntax can be available to access the property through the accessors from within the class (something that will be less likely to be used).