1

I need to perform the same operation if an object passed to a method is either of acceptable types. Is it possible to eliminate the second case in the example below?

obj match {
  case obj: String => print(obj)
  case obj: Int => print(obj)
}
NewlessClubie
  • 983
  • 2
  • 8
  • 18

1 Answers1

4

Yes, it is possible, but not in every case. You can use Scalas | operator in your specific example:

scala> ("hello": Any) match { case s @ (_: String | _: Int) => println(s)}
hello

scala> ("1": Any) match { case s @ (_: String | _: Int) => println(s)}
1

But this specific example only works because println expects an argument of type Any, which is in fact what you have here.

Consider this example:

scala> object X {def f(i: Int) = i.toString; def f(s: String) = s}
defined object X

scala> ("": Any) match { case s @ (_: String | _: Int) => X.f(s)}
<console>:9: error: overloaded method value f with alternatives:
  (s: String)String <and>
  (i: Int)String
 cannot be applied to (Any)
              ("": Any) match { case s @ (_: String | _: Int) => X.f(s)}
                                                                   ^

The problem is that while there are two methods which could handle both types, the compiler can't decide which one should be called. This is because the compiler will infer type Any for s because it can be both String or Int and the compiler needs to chose their common supertype to fulfill this contract. And because there exists no method f which takes an Any you get a compilation error. In this case you need to separate the pattern:

scala> ("hello": Any) match { case s: String => X.f(s) case i: Int => X.f(i)}
res6: String = hello

In summary you should only combine multiple cases when they have the same type, if they don't you have to live with Any. Though, I suggest not to live with Any it is too easy to introduce typing bugs when the code changes.

kiritsuku
  • 52,967
  • 18
  • 114
  • 136
  • Actually, the example I provided in my question is a bit different from what I had in mind. I have an abstract class A with subclasses B,C,D,E and F and a method which accepts A. I need to check the type of a passed object and invoke the same method for B, C and D, but call dedicated methods for E and F. I was thinking of adding a common superclass for B,C and D, but I thought may there is another way – NewlessClubie May 31 '14 at 07:58