How to define "type disjunction" (union types)?
scala
Solution
Well, in the specific case of `Any*`, this trick below won't work, as it will not accept mixed types. However, since mixed types wouldn't work with overloading either, this may be what you want.
First, declare a class with the types you wish to accept as below:
class StringOrInt[T]
object StringOrInt {
implicit object IntWitness extends StringOrInt[Int]
implicit object StringWitness extends StringOrInt[String]
}
Next, declare `foo` like this:
object Bar {
def foo[T: StringOrInt](x: T) = x match {
case _: String => println("str")
case _: Int => println("int")
}
}
And that's it. You can call `foo(5)` or `foo("abc")`, and it will work, but try `foo(true)` and it will fail. This could be side-stepped by the client code by creating a `StringOrInt[Boolean]`, unless, as noted by Randall below, you make `StringOrInt` a `sealed` class.
It works because `T: StringOrInt` means there's an implicit parameter of type `StringOrInt[T]`, and because Scala looks inside companion objects of a type to see if there are implicits there to make code asking for that type work.
Problem
One way that has been suggested to deal with double definitions of overloaded methods is to replace overloading with pattern matching: ``` object Bar { def foo(xs: Any*) = xs foreach { case _:String => println("str") case _:Int => println("int") case _ => throw new UglyRuntimeException() } } ``` This approach requires that we surrender static type checking on the arguments to `foo`. It would be much nicer to be able to write ``` object Bar { def foo(xs: (String or Int)*) = xs foreach { case _: String => println("str") case _: Int => println("int") } } ``` I can get close with `Either`, but it gets ugly fast with more than two types: ``` type or[L,R] = Either[L,R] implicit def l2Or[L,R](l: L): L or R = Left(l) implicit def r2Or[L,R](r: R): L or R = Right(r) object Bar { def foo(xs: (String or Int)*) = xs foreach { case Left(l) => println("str") case Right(r) => println("int") } } ``` It looks like a general (elegant, efficient) solution would require defining `Either3`, `Either4`, .... Does anyone know of an alternate solution to achieve the same end? To my knowledge, Scala does not have built-in "type disjunction". Also, are the implicit conversions defined above lurking in the standard library somewhere so that I can just import them?
Related problems
- What does the `#` operator mean in Scala?
- How can I differentiate between def foo[A](xs: A*) and def foo[A, B](xs: (A, B)*)?
- Is it possible to "curry" higher-kinded types in Scala?
- How do I create a heterogeneous Array in Scala?
- Union type with upper bound
- Selectively disable subsumption in Scala? (correctly type List.contains)