Will I Am
Will I Am

Reputation: 2682

Method polymorphism

I am trying to write a generic method f[T](id:String) that is something like this:

case class A(x:String)
case class B(y:String)
case class C(z:String)

def f[T](id:String): T = { /* equivalent to  T(id) */ }

val result1:A = f[A]("123")   // returns A("123")
val result2:B = f{B]("345")   // returns B("345")
val result3:C = f[C]("567")   // returns C("567")

Unfortunately I cannot figure out how to work with the type T inside the method, besides using reflection. By "working with the type T" i mean for example being able to do something like the following, which I know doesn't work (for illustration purposes only):

   T match { 
             case A => A(id) 
             case B => B(id) 
   }

or simply invoke T(ID) to create a new object of whatever type T is.

I can of course break up this into three methods:

def f1(id:String): A = {  A(id) }
def f2(id:String): B = {  B(id) }
def f3(id:String): C = {  C(id) }

val result1:A = f1("123")   // returns A("123")
val result2:B = f2("345")   // returns B("345")
val result3:C = f3("567")   // returns C("567")

but I'm hoping there is a way to keep it as one generic method to avoid some ugly boilerplate code duplication, and still be nearl as fast as the tree method version.

Upvotes: 0

Views: 48

Answers (1)

Sascha Kolberg
Sascha Kolberg

Reputation: 7162

If you do not want to use reflection (ClassTag or TypeTag), you could use a Factory type class to achieve the desired functionality (unless it defeats the purpose of your generic function by generating a lot of duplicated simple code ;)).

case class A(s: String)
case class B(s: String)
case class C(s: String)

trait Factory[T] extends ((String) => T) {
  def apply(arg: String): T
}

object Factory {
  implicit object AFactory extends Factory[A] {
    override def apply(arg: String): A = A(arg)
  }
  implicit object BFactory extends Factory[B] {
    override def apply(arg: String): B = B(arg)
  }
  implicit object CFactory extends Factory[C] {
    override def apply(arg: String): C = C(arg)
  }
}

def create[T : Factory](arg: String): T = implicitly[Factory[T]].apply(arg)

create[A]("foo") | -> res0: A = A(foo)

Upvotes: 1

Related Questions