user79074
user79074

Reputation: 5270

method overloading with a parameterized type

Just wondering if there is a way to call an overloaded method using a parameterized type. For example define the following object:

object Wrap {

        def f(x: X) = println("x called")
        def f(y: Y) = println("y called")
        def f(a: Any) = println("Any")

        def fp[T](t: T) = f(t)
}

When I test this making the following call

Wrap.fp(new X())

it goes to the call to the Any. Is there a way I can work it such that the appropriate f is called from fp()?

Upvotes: 4

Views: 112

Answers (3)

som-snytt
som-snytt

Reputation: 39577

Use a class tag for assisted matching:

scala> class W[A: ClassTag] { def f(x: X) = 1; def f(y: Y) = 2; def f(a: A) = 3; 
     | def g(x: Any) = x match {
     | case v: X => f(v); case v: Y => f(v); case v: A => f(v); case _ => -1 } }
defined class W

scala> trait Z
defined trait Z

scala> val w = new W[Z]
w: W[Z] = W@1685b453

scala> w g new X {}
res6: Int = 1

scala> w g new Y {}
res7: Int = 2

scala> w g new Z {}
res8: Int = 3

scala> w g "hi"
res9: Int = -1

In a real API, g would take a type parameter that is some supertype of the various params, because nobody writes API that takes Any. The T param in the OP is basically Any, since it is unconstrained.

While I'm editing, we forgot to mention that overloading is evil.

Upvotes: 3

Xiaohe Dong
Xiaohe Dong

Reputation: 5023

def process[A](a: A) = a match {
  case c: X => Wrap f c
  case d: Y => Wrap f d
  case _ => Wrap f a 
}

Upvotes: 1

wheaties
wheaties

Reputation: 35970

Two ways to do it:

First way assumes that X and Y are known types and not generic types. Then you could just do the following:

 def fp: PartialFunction[Any,Unit] ={
   case x: X => println("got x")
   case y: Y => println("got y")
   case _ => println("Any")
 }

and it would work very well without having to do much gymanistics.

Second way, use a type class:

 def fp[T](t: T)(implicit f: Caller[T]) = f(t)

That said, your type class will probably want to look like:

 trait Caller[T]{
   def apply(t: T)
 }

wherein you place the actual things in scope and use the order of resolution to find the final Caller[Any] so that every else takes precedence. So I'd have it be done like this:

 object Wrap{
   implicit val xCal = new Caller[X]{
     def apply(x: X){ println("x called") }
   }
   implicit val yCal = new Caller[Y]{
     def apply(x: Y){ println("y called") }
   }
 }

 object `package`{
   implicit val anyCal = new Caller[Any]{
     def apply(t: Any){ println("any") }
   }
 }

Upvotes: 3

Related Questions