In Java +0.0
is equal to -0.0
for floats and doubles, but not Float.equals
. Is there somewhere where Kotlin clarifies float/double equality? For example:
fun main(args: Array<String>) {
val negZero = -0.0f
val posZero = 0.0f
System.out.println(negZero == posZero)
System.out.println(negZero.equals(posZero))
}
Outputs true
then false
which already negates https://kotlinlang.org/docs/reference/equality.html and makes IntelliJ wrong telling my I can remove the equals
. I have also tested w/ when
statements and it appears to use the ==
approach rather than the Float.equals
. This is the downside of auto-boxing and type aliases. I understand (and prefer) that ==
does a FCMP
/FCMPL
in the bytecode, but the semantics of the equals
method need to be made clear. For example, what does the following output?
fun main(args: Array<String>) {
val negZero = -0.0f
val posZero = 0.0f
val negZeroAsAny: Any = negZero
System.out.println(negZeroAsAny == posZero)
}
As might be expected knowing that casting to Any
boxes it making ==
now properly use equals
. This issue is obvious in Java because using ==
is always one thing and equals
is always another. So…
- Is the fact that IntelliJ telling me I can replace
equals
with==
a bug? - Are the language designers ok with casting to
Any
changing the semantics off the value? - Do caveats on https://kotlinlang.org/docs/reference/equality.html need to be added about
==
not always beingequals
?
My suggestion:
Java got it wrong with Float.equals
and should have had strictEquals
instead. Since Kotlin aims to have a minimal runtime, it can’t really have its own Float
with equals
defined more literally. Similarly, it is impossible to know whether an Any
is a float/double (and runtime introspection is unacceptable), so the ==-is-equals will have to persist. Since Kotlin is stuck with “==
is equals
except for primitives where it uses Java equality semantics”, I think some statement should just be made somewhere (if it isn’t already, I cannot find it). IIRC Scala has to deal with this same thing and just does what Kotlin does which is to have unexpected equality when implicitly boxing in these rare cases to save performance…I have not checked.
(I am sure the same happens with NaN where == is different than equals)
Edit: Now I see Intrinsics.java
, but I don’t see where areEqual(Float, Float)
would be called? Still can’t reasonably check for instanceof Float in the object one due to performance issues IMO.