Hi,
I would like to learn more about the reasoning behind implementing co-operative equality among the various numeric types defined in Spire. Until today I was unaware that Scala did this as well. A BigInt can equal an Int and vice versa. It needs to be vice versa because of the equals contract, which requires symmetry. One thing I noticed in Spire is that the code didn't seem to be ensuring symmetry, and in some quick I did find this one example:
scala> import spire.math._
import spire.math._
scala> val u = UInt(3)
u: spire.math.UInt = 3
scala> val n = Natural(3)
n: spire.math.Natural = 3
scala> u equals n
res0: Boolean = false
scala> n equals u
res1: Boolean = true
I suspect that could be made symmetric, because it should be possible to teach all of Spire's numeric types to recognize the other types to which they can be equal. I also noticed that == is overloaded in some places, leading to apparent inconsistencies, like:
scala> u == 3
res6: Boolean = true
scala> 3 == u
<console>:12: warning: comparing values of types Int and spire.math.UInt using `==' will always yield false
3 == u
^
res7: Boolean = false
But this is just with the == operator, because it is overloaded on the UInt side. When using equals it is symmetric (though inconsistent with ==):
scala> u equals 3
res8: Boolean = false
scala> 3 equals u
res9: Boolean = false
So I'm also curious about what the goal of overloading == is. That seems like it would surprise users.
But mainly I was just surprised myself today that Scala was allowing Ints, BigInts, BigDecimals and others to equal each other. The reason is this is actually the first real use case I have ever seen that "needs" Java's universal equality, where anything can be compared with anything, including unrelated types that cooperate and allow themselves to equal each other. The lowest common supertype of Int and BigInt is Any, but they can equal each other. Because the type passed to equals is Any, you can ask an Int if it is equal to a BigInt, and vice versa.
Since Spire seems to be trying to do a similar kind of thing, letting diverse numeric types equal each other, I wanted to ask here why. Is this cooperative equality among numeric types something needed by specific use cases, something that seemed like it would be more convenient for users? Did you consider just letting Numerics equal Numerics, and UInts equal UInts, and then letting people call methods like .toUInt and .toNumeric? Maybe I just answered my own question, because you probably can't convert all Numerics to UInts. But regardless, I'd like to hear the actual motivation.
Thanks.
Bill