Essentially, what I would like to do is write overloaded versions of "map" for a custom class such that each version of map differs only by the type of function passed to it.
This is what I would like to do:
object Test { case class Foo(name: String, value: Int) implicit class FooUtils(f: Foo) { def string() = s"${f.name}: ${f.value}" def map(func: Int => Int) = Foo(f.name, func(f.value)) def map(func: String => String) = Foo(func(f.name), f.value) } def main(args: Array[String]) { def square(n: Int): Int = n * n def rev(s: String): String = s.reverse val f = Foo("Test", 3) println(f.string) val g = f.map(rev) val h = g.map(square) println(h.string) } } Of course, because of type erasure, this won't work. Either version of map will work alone, and they can be named differently and everything works fine. However, it is very important that a user can call the correct map function simply based on the type of the function passed to it.
In my search for how to solve this problem, I cam across TypeTags. Here is the code I came up with that I believe is close to correct, but of course doesn't quite work:
import scala.reflect.runtime.universe._ object Test { case class Foo(name: String, value: Int) implicit class FooUtils(f: Foo) { def string() = s"${f.name}: ${f.value}" def map[A: TypeTag](func: A => A) = typeOf[A] match { case i if i =:= typeOf[Int => Int] => f.mapI(func) case s if s =:= typeOf[String => String] => f.mapS(func) } def mapI(func: Int => Int) = Foo(f.name, func(f.value)) def mapS(func: String => String) = Foo(func(f.name), f.value) } def main(args: Array[String]) { def square(n: Int): Int = n * n def rev(s: String): String = s.reverse val f = Foo("Test", 3) println(f.string) val g = f.map(rev) val h = g.map(square) println(h.string) } } When I attempt to run this code I get the following errors:
[error] /src/main/scala/Test.scala:10: type mismatch; [error] found : A => A [error] required: Int => Int [error] case i if i =:= typeOf[Int => Int] => f.mapI(func) [error] ^ [error] /src/main/scala/Test.scala:11: type mismatch; [error] found : A => A [error] required: String => String [error] case s if s =:= typeOf[String => String] => f.mapS(func) It is true that func is of type A => A, so how can I tell the compiler that I'm matching on the correct type at runtime?
Thank you very much.