In C# I can overload methods on generic type as shown in the example below:
// http://ideone.com/QVooD
using System;
using System.Collections.Generic;
public class Test {
public static void Foo(List<int> ints) {
Console.WriteLine("I just print");
}
public static void Foo(List<double> doubles) {
Console.WriteLine("I iterate over list and print it.");
foreach(var x in doubles)
Console.WriteLine(x);
}
public static void Main(string[] args) {
Foo(new List<int> {1, 2});
Foo(new List<double> {3.4, 1.2});
}
}
However if I try to do the same in Scala, it will raise a compile time error that List[Int]
and List[Double]
erase to the same type due to erasure. I heard Scala's Manifest
s can be used to work around this, but I don't know how. I didn't find anything helpful in the docs either.
So my question is: How do I use Manifest
s (or whatever else that works) to overload methods over generic types that erase to same type due to erasure?
You would not do it like that in Scala. Why try to emulate something that can never work properly given JVM restrictions? Try idiomatic Scala instead:
trait Fooable[T] {
def foo : Unit
}
object IntListFoo extends Fooable[List[Int]] {
def foo {
println("I just print")
}
}
class DoubleListFoo(val l : List[Double]) extends Fooable[List[Double]] {
def foo {
println("I iterate over list and print it.")
l.foreach { e =>
println(e)
}
}
}
implicit def intlist2fooable(l : List[Int]) = IntListFoo
implicit def doublelist2fooable(l : List[Double]) = new DoubleListFoo(l)
Then, you can execute code like
List(1,2,3,4).foo
List(1.0,2.0,3.0).foo
The Manifest won't really help either becuase those will have the same type after erasure.
What will help having different numbers of arguments (or different types after erasure). I find having different numbers of implicit arguments can transparently solve this problem, and by using scala.Predef.DummyImplicit
, you don't even have to import an implicit anywhere.
class Test{
def foo(ints : List[Int])
def foo(doubles : List[Double])(implicit i1:DummyImplicit)
def foo(strings : List[String])(implicit i1:DummyImplicit, i2:DummyImplicit)
}
Kinda hackish, and both methods need the same return type (here: Unit)...
def fooInt(list: List[Int]) = println("int")
def fooDouble(list: List[Double]) = println("double")
def foo[N <: AnyVal](list:List[N])(implicit m:ClassManifest[N]) = m.erasure match {
case c if c == classOf[Int] => fooInt(list.asInstanceOf[List[Int]])
case c if c == classOf[Double] => fooDouble(list.asInstanceOf[List[Double]])
case _ => error("No soup for you!")
}
foo(List(1,2,3,4))
//--> int
foo(List(1.0,2.0,3.0))
//--> double
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With