Reputation: 18034
I have some overloaded methods that take in multiple types and return the same type:
def foo(x: Int): Foo = ...
def foo(x: String): Foo = ...
def foo(x: Boolean): Foo = ...
def foo(x: Long): Foo = ...
Now I want to define a single way to call the method, something like:
def bar(x: Int | String | Boolean | Long) = foo(x) // how to do this?
I can do it the "naive" way which I don't like very much:
def bar(x: Any) = x match {
case i:Int => foo(i)
case s:String => foo(s)
case b:Boolean => foo(b)
case l:Long => foo(l)
case _ => throw new Exception("Unsupported type")
}
Is there a better way, perhaps using Scalaz or some other library?
Upvotes: 2
Views: 1016
Reputation: 51703
Try type class
trait FooDoer[T] {
def foo(x: T): Foo
}
object FooDoer {
implicit val int: FooDoer[Int] = (x: Int) => foo(x)
implicit val string: FooDoer[String] = (x: String) => foo(x)
implicit val boolean: FooDoer[Boolean] = (x: Boolean) => foo(x)
implicit val long: FooDoer[Long] = (x: Long) => foo(x)
}
def bar[T](x: T)(implicit fooDoer: FooDoer[T]): Foo = fooDoer.foo(x)
bar(1)
bar("a")
bar(true)
bar(1L)
// bar(1.0) // doesn't compile
Also sometimes the following can help
def bar[T](x: T)(implicit ev: (T =:= Int) | (T =:= String) | (T =:= Boolean) | (T =:= Long)) = ???
trait |[A, B]
trait LowPriority_| {
implicit def a[A, B](implicit a: A): A | B = null
}
object | extends LowPriority_| {
implicit def b[A, B](implicit b: B): A | B = null
}
How to define "type disjunction" (union types)?
Upvotes: 4
Reputation: 27421
A typeclass might work like this:
trait CanFoo[T] {
def foo(t: T): Foo
}
object CanFoo {
implicit object intFoo extends CanFoo[Int] {
def foo(i: Int) = Foo(i)
}
implicit object stringFoo extends CanFoo[String] {
def foo(s: String) = Foo(s)
}
implicit object boolFoo extends CanFoo[Boolean] {
def foo(i: Boolean) = Foo(i)
}
implicit object longFoo extends CanFoo[Long] {
def foo(i: Long) = Foo(i)
}
}
def bar[T](x: T)(implicit ev: CanFoo[T]) =
ev.foo(x)
bar(0)
bar("hello")
bar(true)
bar(0.toLong)
Upvotes: 1