14

Is it possible for a pattern match to detect if something is a Numeric? I want to do the following:

class DoubleWrapper(value: Double) {
  override def equals(o: Any): Boolean = o match {
    case o: Numeric => value == o.toDouble
    case _ => false
  }
  override def hashCode(): Int = value ##
}

But of course this doesn't really work because Numeric isn't the supertype of things like Int and Double, it's a typeclass. I also can't do something like def equals[N: Numeric](o: N) because o has to be Any to fit the contract for equals.

So how do I do it without listing out every known Numeric class (including, I guess, user-defined classes I may not even know about)?

dhg
  • 52,383
  • 8
  • 123
  • 144
  • the problem is not solvable as pointed out in answers below, but you could hack it (convert to string and parse as double, i suppose!). like most hacks, it stinks but can work :-). Another hack could be a regex match on the value... but really, do you need to bother about anything that is not Double in the case above? Could the calling code not follow a convention? Does the calling code really need all different sorts of number representations? why redefine equals on Double? food for thought i guess... – aishwarya Aug 19 '12 at 14:22

2 Answers2

5

The original problem is not solvable, and here is my reasoning why:

To find out whether a type is an instance of a typeclass (such as Numeric), we need implicit resolution. Implicit resolution is done at compile time, but we would need it to be done at runtime. That is currently not possible, because as far as I can tell, the Scala compiler does not leave all necessary information in the compiled class file. To see that, one can write a test class with a method that contains a local variable, that has the implicit modifier. The compilation output will not change when the modifier is removed.

Kim Stebel
  • 41,826
  • 12
  • 125
  • 142
  • This is not true, scalac stores information if something is implicit: https://github.com/scala/scala/blob/master/src/reflect/scala/reflect/api/Symbols.scala#L239 – kiritsuku Aug 19 '12 at 08:48
  • 1
    What is more important than whether runtime information about implicits is available, is the fact that implicit resolution is a matter of scoping, e.g. importing symbols. There is just no way this could be meaningfully done at runtime. The result is the same: The "problem" is not solvable. It is solvable for a given set of types that you want to check, e.g. the primitives. Otherwise you need to design an interface for 'registering' comparable types. – 0__ Aug 19 '12 at 12:33
  • I completely agree, there are many reasons why it won't work. – Kim Stebel Aug 19 '12 at 13:57
0

Are you using DoubleWrapper to add methods to Double? Then it should be a transparent type, i.e. you shouldn't be keeping instances, but rather define the pimped methods to return Double instead. That way you can keep using == as defined for primitives, which already does what you want (6.0 == 6 yields true).


Ok, so if not, how about

override def equals(o: Any): Boolean = o == value

If you construct equals methods of other wrappers accordingly, you should end up comparing the primitive values again.

Another question is whether you should have such an equals method for a stateful wrapper. I don't think mutable objects should be equal according to one of the values they hold—you will most likely run into trouble with that.

0__
  • 66,707
  • 21
  • 171
  • 266
  • No, I'm not. My actual class is indeed storing state, not just adding methods to Double. – dhg Aug 18 '12 at 21:30
  • I like your suggestion since it avoids the problem (though I'm still curious if the original problem is solvable). And I agree about the design of the equality method (since it won't be symmetric), but I'm ok with that. – dhg Aug 18 '12 at 22:02