I want to create extension functions for classes that encapsulate simple Number
s. For example DoubleProperty
. I encountered the problem, that I can't overload the +
and the +=
operator at the same time.
I wan't to create a behaviour, that passes following tests:
class DoublePropertyTest {
lateinit var doubleProperty: DoubleProperty
@Before
fun initialize() {
doubleProperty = SimpleDoubleProperty(0.1)
}
@Test
fun plus() {
val someProperty = doubleProperty + 1.5
assertEquals(someProperty.value, 1.6, 0.001)
}
@Test
fun plusAssign() {
val someProperty = doubleProperty
doubleProperty += 1.5 //error if + and += are overloaded
assert(someProperty === doubleProperty) //fails with only + overloaded
assertEquals(doubleProperty.value, 1.6, 0.001)
}
}
It could be implemented using these extension functions:
operator fun ObservableDoubleValue.plus(number: Number): DoubleProperty
= SimpleDoubleProperty(get() + number.toDouble())
operator fun WritableDoubleValue.plusAssign(number: Number)
= set(get() + number.toDouble())
The problem is, that if +
is overlodaded the +=
can't be overloaded aswell:
Assignment operators ambiguity. All these functions match.
- public operator fun ObservableDoubleValue.plus(number: Number): DoubleProperty
- public operator fun WritableDoubleValue.plusAssign(number: Number): Unit
If I only overload the +
operator, a new DoubleProperty
object is returned on +=
operations instead of the initial one.
Is there a way to work around this limitation?
You cannot overload both
+
and+=
. Overload one of the them.I copied/pasted from Kotlin in Action book!
The strange
+=
operator in Kotlinyou can both overloading the
plus
operator andplusAssign
operator in kotlin, but you must following the rules of kotlin to solving the strange+=
conflicts.the kotlin has already done such things in the
stdlib
for theCollection
& theMap
classes, the Collection#plus and MutableCollection#plusAssign as below:But wait, how to solving the conflict when we using the
+=
operator?IF the list is an immutable
Collection
then you must define a mutablevar
variable, then theplus
operator is used since its internal state can't be edited. for example:IF the list is a mutable
MutableCollection
then you must define a immutableval
variable, then theplusAssign
operator is used since its internal state can be edited anywhere. for example:On the other hand, you can overloads an operator with diff signatures, each signature for the different context, and kotlin also do it, e.g: Collection#plus. for example:
Your operator override implementation has two problems:
1. inconsistent type after
plus
Any
ObservableDoubleValue
instance plus aNumber
, got aDoubleProperty
instance(or say aSimpleDoubleProperty
instance). Let's say I have a typeComplexDoubleProperty
implementsObservableDoubleValue
, you will see:You can see this behavior makes no sense.
2. a=a+b and a+=b should be identical
If your implementation compiles, you will have
prints
true
because+=
sets the value to the original instance. If you replacea+=0.1
witha=a+0.1
you will getfalse
because a new instance is returned. Generally speaking,a=a+b
anda+=b
are not identical in this implementation.To fix the two problems above, my suggestion is
so you don't need to override
plusAssign
. The solution is not as general as yours, but it's correct if you only haveSimpleDoubleProperty
calculations, and I believe you do, because in your implementation,plus
always returns aSimpleDoubleProperty
instance.If
DoubleProperty
is your class, you can makeplus
andplusAssign
its methods, that should resolve any ambiguity.