10

Suppose I have

def foo(x: Any) = x match {
  case s: String => println(0)
  case i: Int => println(1)
  case l: Long => println(2)
  //...
}

Is there any way to make something like the following?

def foo(x: Any) = x match {
  case s: String => println(0)
  case i: Numeric => println("Numeric")
}
tkroman
  • 4,811
  • 1
  • 26
  • 46

2 Answers2

6

You could match against the Number interface:

def foo(x: Any) = x match {
  case s: String => println(0)
  case i: java.lang.Number => println("Numeric")
}
Lee
  • 142,018
  • 20
  • 234
  • 287
  • This kind of matching is discouraged as it's synonym for type-casting, which is possible but is considered 'bad style' in functional programming. – Rajish Nov 05 '13 at 07:49
  • Well there is no idiomatic way is there, so this is rather encouraged for this scenario - till Scala catches up with Java.. – matanster Sep 26 '14 at 02:10
5

You could try this:

def foo[A](x: A)(implicit num: Numeric[A] = null) = Option(num) match {
  case Some(num) => println("Numeric: " + x.getClass.getName)
  case None => println(0)
}

Then this

foo(1)
foo(2.0)
foo(BigDecimal(3))
foo('c')
foo("no")

will print

Numeric: java.lang.Integer
Numeric: java.lang.Double
Numeric: scala.math.BigDecimal
Numeric: java.lang.Character
0

Note that obtaining a null implicit parameter would not mean that no such implicit exist, but just that none was found at compile time in the search scope for implicits.

Jean-Philippe Pellet
  • 59,296
  • 21
  • 173
  • 234
  • That is a tricky one! What a pity I can't accept both answers. – tkroman Nov 03 '13 at 20:18
  • Is there a (nice) way to avoid the `null` value? (E.g. providing an implicit `Option[Numeric[A]]`?) – r0estir0bbe Oct 26 '15 at 09:26
  • All tricks that I can think of would be considerably less readable and not substantially safer. – Jean-Philippe Pellet Oct 26 '15 at 09:30
  • That's what I suspected. Thanks for clarifying! – r0estir0bbe Oct 26 '15 at 13:45
  • I noticed that this solution does not work if the numeric values are typed as `Any` and then passed to the method, e.g. `val x: Any = 3.14; foo(x)` will print `0`. In that case, only the solution of the accepted answer is working as intended. I need this functionality because I want to extract any numeric value as `double` from `Map[String, Any]`. Is there some way to change this method to work with `Any` as well? I prefer using `Numeric` instead of pattern matching `java.lang.Number`. – r0estir0bbe Oct 26 '15 at 16:19
  • Right. Implicits are a compile-time mechanism, and if the compiler thinks it's passing an `Any`, it can't supply a `Numeric`. – Jean-Philippe Pellet Oct 26 '15 at 16:22