Proposal
Add a “pseudo-assign” operator <- (hopefully with a better name) .
The function would be:
operator fun pesudoAssign(value: <T>): Unit
It has the same structure as the plusAssign function.
This allows for adding behavior to “assignments” without changing the behavior of the = operator.
This is already possible by overloading an augmented assignment operator (e.g. +=) or even get or invoke, but using += for this behavior is ugly and ambiguous. I think pseudo-assignment would have enough use cases to be worth giving its own operator (given that there is enough uses to add inline classes, and these are extremely useful for them).
Inline classes could even be given a <- operator by default for their internal property.
Examples
data class Wrapper(var v: Int){
operator fun pesudoAssign(value: Number){ v = value.toInt() }
operator fun pesudoAssign(value: String){ v = value.toInt() }
}
data class Example2(var v: Int, val map: MutableMap<String, String>){
operator fun pesudoAssign(value: Number){ v = value.toInt() }
operator fun pesudoAssign(value: Map<String, String>){
map.clear()
map.putAll(value)
}
}
// innerValue is a placeholder for however this would be done in the Int class
operator fun Double.pesudoAssign(value: Number){ innerValue = value.toDouble() }
fun main(args: Array<String>){
val wrapped = Wrapper(4)
wrapped <- 3
println(wrapped.value) // prints 3
wrapped <- "90"
println(wrapped.value) // prints 90
val doub = 4.5
doub <- 7
println(doub) // prints 7.0
}
Use Cases
Wrapper types (especially with upcoming inline classes).
Pesudo-assign to different properties depending on type.
Use a single pesudo-assignment to set multiple properties (e.g. pesudo-assign a pair, assign the first value to one property, and the second to a different property).
Optional, explicitly defined (pseudo-)assignment compatibility (e.g. pseudo-assign a Double to an Int).
Additional behavior on pesudo-assignment (e.g. pesudo-assign an id, make a database request to get property values for that id).
In general, there seem to be two main use cases: assigning to an internal variable or allowing assignment compatibility with a different type.
Similarity to Implicit Casting
This is notably similar to implicit casting, which is (thankfully) not going to be part of Kotlin. There are a few notable differences that keep this from having the same problems:
- The possibility for other behavior (like accessing properties, see the Wrapper example).
- No actual casting occurs.
- There much less ambiguity, no more than other operators.
Plus, pseudo-assignment is already achievable using existing operators, this would just give it its own operator.
Caveat: Object Creation
There are cases where you would want to pesudo-assign an entirely new object. For example, if you have a class that queries data for an id (such as an Exposed DAO class) and a ← operator that changes the id, it would be easier to return an entirely new object for the new id, that then would be assigned to the left-hand variable. However, I didn’t see an easy way to implement that (without having two very very similar operators), and there aren’t that many use cases (and they are all doable by changing properties, although it can get messy).