How to do generic tuple -> case class conversion in Scala? - scala

Let's say someone provided a function:
def getTupleData[T](source: String): List[T] = {
// ...
}
I need to write a function which takes a case class C as the type parameter and return List[C] with the help of the above function. Here is what I have got so far:
def getCaseClassData[C](source: String): List[C] = {
// Somehow get T from C.
// For example, if C is case class MyCaseClass(a: Int, b: Long), then T is (Int, Long)
// How to get T?
getTupleData[T](source) map { tuple: T =>
// Somehow convert tuple into a case class instance with the case class type parameter
// C.tupled(tuple) ?? Type parameter cannot be used like this. :(
}
}
More specifically, it seems to me I'm asking two questions here:
How to explicitly obtain the type of the tuple from a type parameter which represents a case class so that it can be used as a type parameter?
How to create a case class instance from a tuple instance without knowing the actual name of the case class but only a type parameter?

You won't find any reasonably simple or direct way to do it. If you' re ready for the more involved solutions, bear with me.
Every case class has an apply method in its companion object, which instantiates the class. By calling tupled on this method (after eta-expansion), you'll get a function that takes a tuple and creates the corresponding case class instance.
Now of course the problem is that the every case class's apply has a different signature. We can get around this by introducing a type class representing a case class factory, and provide instances of this type class through a macro (which will just delegate to the case class's apply method).
import scala.reflect.macros.whitebox.Context
import scala.language.experimental.macros
trait CaseClassFactory[C,T]{
type Class = C
type Tuple = T
def apply(t: Tuple): C
}
object CaseClassFactory {
implicit def factory1[C,T]: CaseClassFactory[C,T] = macro factoryImpl[C,T]
implicit def factory2[C]: CaseClassFactory[C,_] = macro factoryImpl[C,Nothing]
def apply[C,T]: CaseClassFactory[C,T] = macro factoryImpl[C,T]
def apply[C]: CaseClassFactory[C,_] = macro factoryImpl[C,Nothing]
def factoryImpl[C:c.WeakTypeTag,T:c.WeakTypeTag](c: Context) = {
import c.universe._
val C = weakTypeOf[C]
val companion = C.typeSymbol.companion match {
case NoSymbol => c.abort(c.enclosingPosition, s"Instance of $C has no companion object")
case sym => sym
}
val tupledTree = c.typecheck(q"""($companion.apply _).tupled""")
val T = tupledTree.tpe match {
case TypeRef(_, _, List(argTpe, _)) => argTpe
case t => c.abort(c.enclosingPosition, s"Expecting type constructor (Function1) for $C.tupled, but got $t: ${t.getClass}, ${t.getClass.getInterfaces.mkString(",")}")
}
if (! (c.weakTypeOf[T] <:< T)) {
c.abort(c.enclosingPosition, s"Incompatible tuple type ${c.weakTypeOf[T]}: not a sub type of $T")
}
q"""
new CaseClassFactory[$C,$T] {
private[this] val tupled = ($companion.apply _).tupled
def apply(t: Tuple): $C = tupled(t)
}
"""
}
}
With it you can do something like this:
scala> case class Person(name: String, age: Long)
defined class Person
scala> val f = CaseClassFactory[Person]
f: CaseClassFactory[Person]{type Tuple = (String, Long)} = $anon$1#63adb42c
scala> val x: f.Tuple = ("aze", 123)
x: f.Tuple = (aze,123)
scala> implicitly[f.Tuple =:= (String, Long)]
res3: =:=[f.Tuple,(String, Long)] = <function1>
scala> f(("aze", 123))
res4: Person = Person(aze,123)
But more importantly, you can require an instance of CaseClassFactory as an implicit parameter, allowing to generically instantiate your case classes. You can then do something like:
scala> implicit class TupleToCaseClassOps[T](val t: T) extends AnyVal {
| def toCaseClass[C](implicit f: CaseClassFactory[C,T]): C = {
| f(t)
| }
| }
defined class TupleToCaseClassOps
scala> case class Person(name: String, age: Long)
defined class Person
scala> ("john", 21).toCaseClass[Person]
res5: Person = Person(john,21)
Pretty neat. Armed with this type class, getCaseClassData then becomes:
def getCaseClassData[C](source: String)(implicit f: CaseClassFactory[C,_]): List[C] = {
getTupleData[f.Tuple](source) map { tuple: f.Tuple =>
f(tuple)
}
}

Related

Scala, generic tuple

I have a generic method that can accept any tuple of any size, the only constraint is that the first element of this tuple should be of type MyClass.
Something like this:
trait MyTrait[T <: (MyClass, _*)] {
getMyClass(x: T): MyClass = x._1
}
I've tried this
trait MyTrait[T <: (MyClass, _) with (MyClass, _, _) with (MyClass, _, _) with ...] {
getMyClass(x: T): MyClass = x._1
}
but I get the error unboud wildcard type
If you want to do this without either boilerplate or runtime reflection, Shapeless is your best bet. You can use the IsComposite type class to put type-level constraints on the first element of a tuple:
import shapeless.ops.tuple.IsComposite
trait MustBeFirst
class MyClass[P <: Product](p: P)(implicit ev: IsComposite[P] { type H = MustBeFirst }) {
def getMustBeFirst(x: P): MustBeFirst = ev.head(p)
}
And then:
scala> val good2 = (new MustBeFirst {}, "")
good2: (MustBeFirst, String) = ($anon$1#7294acee,"")
scala> val good3 = (new MustBeFirst {}, "", 123)
good3: (MustBeFirst, String, Int) = ($anon$1#6eff9288,"",123)
scala> val good4 = (new MustBeFirst {}, "", 'xyz, 123)
good4: (MustBeFirst, String, Symbol, Int) = ($anon$1#108cdf99,"",'xyz,123)
scala> val bad2 = ("abc", 123)
bad2: (String, Int) = (abc,123)
scala> new MyClass(good2)
res0: MyClass[(MustBeFirst, String)] = MyClass#5297aa76
scala> new MyClass(good3)
res1: MyClass[(MustBeFirst, String, Int)] = MyClass#3f501844
scala> new MyClass(good4)
res2: MyClass[(MustBeFirst, String, Symbol, Int)] = MyClass#24e15478
scala> new MyClass(bad2)
<console>:15: error: could not find implicit value for parameter ev: shapeless.ops.tuple.IsComposite[(String, Int)]{type H = MustBeFirst}
new MyClass(bad2)
^
If you need to use a trait, you can put the ev (for "evidence") requirement inside the definition instead of in the constructor:
trait MyTrait[P <: Product] {
implicit def ev: IsComposite[P] { type H = MustBeFirst }
}
Now any class instantiating MyTrait will have to provide evidence that P is a tuple with MustBeFirst as its first element.
It's a little bit unsafe but you can use Structural type in this case:
trait MyTrait {
def getMyClass(x: {def _1: MyClass}): MyClass = x._1
}
Scala can't use generic tuple with unknown size because Products don's inherit themeselfs. You can try to use Shapeless or Products from play json lib.
This is now possible in Scala 3 and very straightforward:
class MyClass
trait MyTrait[T <: MyClass *: _] {
def getMyClass(x: T): MyClass = x.head
}
The *: infix operator is the type level equivalent of the +: sequence prepend (or :: for lists). So we essentially require type T to be a tuple such that its first member is of type MyClass. Note that the members of generic tuples cannot be retrieved using the usual _1, _2, ... attributes, but should be accessed using list-like methods (head, tail, apply, etc.). More surprising, these methods are type-safe since they carry precise type information.
Demo:
object Test1 extends MyTrait[(MyClass, Int, String)] // Compiles
//object Test2 extends MyTrait[(Int, String)] // Does not compile!
//object Test3 extends MyTrait[EmptyTuple] // Neither does this
val myClass = Test1.getMyClass((new MyClass, 1, "abc"))
summon[myClass.type <:< MyClass] // Compiles
Read more about match types, type inference.
You need to inherit your trait from Product, through which you can have productIterator, productArity and, productElement to handle the returned value. Here is an example
case class MyClass()
trait MyTrait[T <: Product] {
def getMyClass(x: T): Option[MyClass] =
if(
x.productIterator.hasNext
&&
x.productIterator.next().isInstanceOf[MyClass]
){
Some(x.productIterator.next().asInstanceOf[MyClass])
} else {
None
}
}
case class Test() extends MyTrait[Product]
And you can invoke like this
Test().getMyClass((MyClass(), 1,3,4,5))
//res1: Option[MyClass] = Some(MyClass())
Test().getMyClass((1,3,4,5))
//res2: Option[MyClass] = None
Hope this helps you.
If you are looking for compile time guarantee then this is one of the use cases for
Shapeless,
You need to add Shapeless in your build.sbt,
libraryDependencies ++= Seq("
com.chuusai" %% "shapeless" % "2.3.3"
)
Now, you can use Shapeless to define a typesafe getter which comes with compile time guarantees,
scala> import shapeless._
// import shapeless._
scala> import ops.tuple.IsComposite
// import ops.tuple.IsComposite
scala> import syntax.std.tuple._
// import syntax.std.tuple._
scala> case class Omg(omg: String)
// defined class Omg
scala> val myStringTuple = ("All is well", 42, "hope")
// myStringTuple: (String, Int, String) = (All is well,42,hope)
scala> val myOmgTuple = (Omg("All is well"), 42, "hope")
// myOmgTuple: (Omg, Int, String) = (Omg(All is well),42,hope)
Now if you want to enrich your tuples with a "first" getter with a specific type then,
scala> implicit class GetterForProduct[B <: Product](b: B) {
| def getFirst[A](implicit comp: IsComposite[B] { type H = A }): A = b.head
| }
// defined class GetterForProduct
scala> val myString = myStringTuple.getFirst[String]
// myString: String = All is well
scala> val myOmgError = myOmgTuple.getFirst[String]
// <console>:24: error: could not find implicit value for parameter comp: shapeless.ops.tuple.IsComposite[(Omg, Int, String)]{type H = String}
// val myOmgError = myOmgTuple.getFirst[String]
// ^
scala> val myOmg = myOmgTuple.getFirst[Omg]
// myOmg: Omg = Omg(All is well
If you don't need the implicit enrichment and are just looking for a way to "lock" the type in a getter and use it for corresponding types,
scala> trait FirstGetterInProduct[A] {
| def getFirst[B <: Product](b: B)(implicit comp: IsComposite[B] { type H = A }): A = b.head
| }
// defined trait FirstGetterInProduct
scala> object firstGetterInProductForString extends FirstGetterInProduct[String]
// defined object firstGetterInProductForString
scala> object firstGetterInProductForOmg extends FirstGetterInProduct[Omg]
// defined object firstGetterInProductForOmg
// Right tuple with right getter,
scala> val myString = firstGetterInProductForString.getFirst(myStringTuple)
// myString: String = All is well
// will fail at compile time for tuple with different type for first
scala> val myOmgError = firstGetterInProductForString.getFirst(myOmgTuple)
// <console>:23: error: could not find implicit value for parameter comp: shapeless.ops.tuple.IsComposite[(Omg, Int, String)]{type H = String}
// val myOmgError = firstGetterInProductForString.getFirst(myOmgTuple)
// ^
scala> val myOmg = firstGetterInProductForOmg.getFirst(myOmgTuple)
// myOmg: Omg = Omg(All is well)

Scala case class with multiple-type argument

I need to check integrity of nested schemas and hence am writing case classes to do so. The main hurdle I am facing is the schema may have a field (say, name) either of a String or a Utf8 type and I want to accept both the instances. Is it possible to avoid having two case classes as
case class NameValueString(name: String, value: Double)
case class NameValueUtf8(name: Utf8, value: Double)
and something like
case class NameValue(name #(_:String | _:Utf8), value: Double)
The above expression certainly fails compilation.
Nikhil
One approach is so-called type classes:
trait StringLike[A] // sealed if you don't want anybody to implement it elsewhere
object StringLike {
implicit object StringEv extends StringLike[String] {}
implicit object Utf8Ev extends StringLike[Utf8] {}
}
case class NameValue[A](name: A, value: Double)(implicit val stringLike: StringLike[A])
Of course, StringLike will normally not be empty, but describe whatever common functionality you need from both String and Utf8.
You can match on the evidence:
def nameLength[A](nameValue: NameValue[A]) = nameValue.stringLike match {
case StringLike.StringEv =>
nameValue.name.length // calls String#length
case StringLike.Utf8Ev =>
nameValue.name.length // calls Utf8#length (assuming Utf8 has such method)
}
In this case the compiler will even know that A (and so the type of nameValue.name) is String in the first branch and Utf8 in the second.
Another pattern (doesn't require implicit arguments):
import scala.language.implicitConversions
class StringLike[A](name: A) {
override def toString = {
name match {
case s: String => s"String: $s"
case i: Int => s"Int: $i"
}
}
}
implicit def string2StringLike(s: String) = new StringLike(s)
implicit def int2StringLike(i: Int) = new StringLike(i)
case class NameValue[A](name: StringLike[A], value: String) {
override def toString = name.toString
}
NameValue("123", "123")
//> NameValue[String] = String: 123
NameValue(13, "123")
//> NameValue[Int] = Int: 13
NameValue(13.9, "123")
// error: type mismatch;
// found : Double(13.9)
// required: StringLike[?]
// NameValue(13.9, "123")
// ^
UPDATE
Here's how I see completed type class approach based on Alexey's answer:
trait StringLike[A] {
def toString(x: A): String
}
object StringLike {
implicit object StringStringLike extends StringLike[String] {
def toString(s: String) = s"String: $s"
}
implicit object IntStringLike extends StringLike[Int] {
def toString(i: Int) = s"Int: $i"
}
}
import StringLike._
case class NameValue[A](name: A, value: Double)(implicit ev: StringLike[A]) {
override def toString = ev.toString(name)
}
NameValue(1, 2.0)
//> NameValue[Int] = Int: 1
NameValue("123", 2.0)
//> NameValue[String] = String: 123
NameValue(2.0, 2.0)
// error: could not find implicit value for parameter ev:
// StringLike[Double]
// NameValue(2.0, 2.0)
// ^
UPDATE2
One more (using union type for type safety):
type ¬[A] = A => Nothing
type ¬¬[A] = ¬[¬[A]]
type ∨[T, U] = ¬[¬[T] with ¬[U]]
type |∨|[T, U] = { type λ[X] = ¬¬[X] <:< (T ∨ U) }
def nameLength[A: ClassTag: (Int |∨| String)#λ](nameValue: NameValue[A]) =
nameValue.name match {
case s:String => s.length
case i:Int => i + 1
}
As you are using case class already, if you just need different ways to create it, and you are ok on keeping your data represented in only one way, you can add your own apply method to enable the creation using different parameters.
case class NameValue(name: String, value: Double)
object NameValue{
def apply(name: Utf8, value: Double): NameValue = {
new NameValue( name.toString, value )
}
}
Alternatively, if you would like to pattern match and extract NameValue from different options, you may need to check Extractors, which is basically create your own unapply methods... check http://danielwestheide.com/blog/2012/11/21/the-neophytes-guide-to-scala-part-1-extractors.html

In Scala Reflection, How to get generic type parameter of a concrete subclass?

Assuming that I have a Generic superclass:
class GenericExample[T](
a: String,
b: T
) {
def fn(i: T): T = b
}
and a concrete subclass:
case class Example(
a: String,
b: Int
) extends GenericExample[Int](a, b)
I want to get the type parameter of function "fn" by scala reflection, so I select and filter through its members:
import ScalaReflection.universe._
val baseType = typeTag[Example]
val member = baseType
.tpe
.member(methodName: TermName)
.asTerm
.alternatives
.map(_.asMethod)
.head
val paramss = member.paramss
val actualTypess: List[List[Type]] = paramss.map {
params =>
params.map {
param =>
param.typeSignature
}
}
I was expecting scala to give me the correct result, which is List(List(Int)), instead I only got the generic List(List(T))
Crunching through the document I found that typeSignature is the culprit:
* This method always returns signatures in the most generic way possible, even if the underlying symbol is obtained from an
* instantiation of a generic type.
And it suggests me to use the alternative:
def typeSignatureIn(site: Type): Type
However, since class Example is no longer generic, there is no way I can get site from typeTag[Example], can anyone suggest me how to get typeOf[Int] given only typeTag[Example]? Or there is no way to do it and I have to revert to Java reflection?
Thanks a lot for your help.
UPDATE: After some quick test I found that even MethodSymbol.returnType doesn't work as intended, the following code:
member.returnType
also yield T, annd it can't be corrected by asSeenFrom, as the following code doesn't change the result:
member.returnType.asSeenFrom(baseType.tpe, baseType.tpe.typeSymbol.asClass)
There are two approaches which I can suggest:
1) Reveal generic type from base class:
import scala.reflect.runtime.universe._
class GenericExample[T: TypeTag](a: String, b: T) {
def fn(i: T) = "" + b + i
}
case class Example(a: String, b: Int) extends GenericExample[Int](a, b) {}
val classType = typeOf[Example].typeSymbol.asClass
val baseClassType = typeOf[GenericExample[_]].typeSymbol.asClass
val baseType = internal.thisType(classType).baseType(baseClassType)
baseType.typeArgs.head // returns reflect.runtime.universe.Type = scala.Int
2) Add implicit method which returns type:
import scala.reflect.runtime.universe._
class GenericExample[T](a: String, b: T) {
def fn(i: T) = "" + b + i
}
case class Example(a: String, b: Int) extends GenericExample[Int](a, b)
implicit class TypeDetector[T: TypeTag](related: GenericExample[T]) {
def getType(): Type = {
typeOf[T]
}
}
new Example("", 1).getType() // returns reflect.runtime.universe.Type = Int
I'm posting my solution: I think there is no alternative due to Scala's design:
The core difference between methods in Scala reflection & Java reflection is currying: Scala method comprises of many pairs of brackets, calling a method with arguments first merely constructs an anonymous class that can take more pairs of brackets, or if there is no more bracket left, constructs a NullaryMethod class (a.k.a. call-by-name) that can be resolved to yield the result of the method. So types of scala method is only resolved at this level, when method is already broken into Method & NullaryMethod Signatures.
As a result it becomes clear that the result type can only be get using recursion:
private def methodSignatureToParameter_ReturnTypes(tpe: Type): (List[List[Type]], Type) = {
tpe match {
case n: NullaryMethodType =>
Nil -> n.resultType
case m: MethodType =>
val paramTypes: List[Type] = m.params.map(_.typeSignatureIn(tpe))
val downstream = methodSignatureToParameter_ReturnTypes(m.resultType)
downstream.copy(_1 = List(paramTypes) ++ methodSignatureToParameter_ReturnTypes(m.resultType)._1)
case _ =>
Nil -> tpe
}
}
def getParameter_ReturnTypes(symbol: MethodSymbol, impl: Type) = {
val signature = symbol.typeSignatureIn(impl)
val result = methodSignatureToParameter_ReturnTypes(signature)
result
}
Where impl is the class that owns the method, and symbol is what you obtained from Type.member(s) by scala reflection

How to define a function whose output type depends on the input type

Given the following classes:
case class AddRequest(x: Int, y: Int)
case class AddResponse(sum: Int)
case class ToUppercaseRequest(str: String)
case class ToUppercaseResponse(upper: String)
How do I define in a typesafe manner some function:
def process(req: ???): ???
Such that the following should hold true:
val r1: AddResponse = process(AddRequest(2, 3))
val r2: ToUppercaseResponse = process(ToUppercaseRequest("aaa"))
Also, the following should not compile:
val r3 = process("somestring")
This is both entirely possible and a totally reasonable thing to do in Scala. This kind of thing is all over Shapeless, for example, and something similar (but less principled) is the basis of the magnet pattern that shows up in Spray, etc.
Update: note that the following solution assumes that "given the following classes" means you don't want to touch the case classes themselves. If you don't care, see the second part of the answer below.
You'd want a type class that maps input types to output types:
case class AddRequest(x: Int, y: Int)
case class AddResponse(sum: Int)
case class ToUppercaseRequest(str: String)
case class ToUppercaseResponse(upper: String)
trait Processable[In] {
type Out
def apply(in: In): Out
}
And then some type class instances:
object Processable {
type Aux[I, O] = Processable[I] { type Out = O }
implicit val toUppercase: Aux[ToUppercaseRequest, ToUppercaseResponse] =
new Processable[ToUppercaseRequest] {
type Out = ToUppercaseResponse
def apply(in: ToUppercaseRequest): ToUppercaseResponse =
ToUppercaseResponse(in.str.toUpperCase)
}
implicit val add: Aux[AddRequest, AddResponse] =
new Processable[AddRequest] {
type Out = AddResponse
def apply(in: AddRequest): AddResponse = AddResponse(in.x + in.y)
}
}
And now you can define process using this type class:
def process[I](in: I)(implicit p: Processable[I]): p.Out = p(in)
Which works as desired (note the appropriate static types):
scala> val res: ToUppercaseResponse = process(ToUppercaseRequest("foo"))
res: ToUppercaseResponse = ToUppercaseResponse(FOO)
scala> val res: AddResponse = process(AddRequest(0, 1))
res: AddResponse = AddResponse(1)
But it doesn't work on arbitrary types:
scala> process("whatever")
<console>:14: error: could not find implicit value for parameter p: Processable[String]
process("whatever")
^
You don't even have to use a path dependent type (you should be able just to have two type parameters on the type class), but it makes using process a little nicer if e.g. you have to provide the type parameter explicitly.
Update: everything above assumes that you don't want to change your case class signatures (which definitely isn't necessary). If you are willing to change them, though, you can do this a little more concisely:
trait Input[Out] {
def computed: Out
}
case class AddRequest(x: Int, y: Int) extends Input[AddResponse] {
def computed: AddResponse = AddResponse(x + y)
}
case class AddResponse(sum: Int)
case class ToUppercaseRequest(str: String) extends Input[ToUppercaseResponse] {
def computed: ToUppercaseResponse = ToUppercaseResponse(str.toUpperCase)
}
case class ToUppercaseResponse(upper: String)
def process[O](in: Input[O]): O = in.computed
And then:
scala> process(AddRequest(0, 1))
res9: AddResponse = AddResponse(1)
scala> process(ToUppercaseRequest("foo"))
res10: ToUppercaseResponse = ToUppercaseResponse(FOO)
Which kind of polymorphism (parametric or ad-hoc) you should prefer is entirely up to you. If you want to be able to describe a mapping between arbitrary types, use a type class. If you don't care, or actively don't want this operation to be available for arbitrary types, using subtyping.
You can define a common trait for Requests, and a common trait for Responses where the request type is defined for specific response type:
trait Request[R <: Response]
trait Response
case class AddRequest(x: Int, y: Int) extends Request[AddResponse]
case class AddResponse(sum: Int) extends Response
case class ToUppercaseRequest(str: String) extends Request[ToUppercaseResponse]
case class ToUppercaseResponse(upper: String) extends Response Response[ToUppercaseRequest]
Then, process signature would be:
def process[A <: Request[B], B <: Response](req: A): B
When you call process, you'll have to explicitly define the types so that the returned type is what you expect it to be - it can't be inferred specifically enough:
val r1: AddResponse = process[AddRequest, AddResponse](AddRequest(2, 3))
val r2: ToUppercaseResponse = process[ToUppercaseRequest, ToUppercaseResponse](ToUppercaseRequest("aaa"))

How do I setup multiple ORed type bounds in Scala

Is it possible to do something like this in Scala:
class MyTest {
def foo[A <: String _or_ A <: Int](p:List[A]) = {}
}
That is, the type A could be a String or Int. Is this possible?
(Similar question here)
Not really possible as you put it, but you can do it using the type class pattern. For example, from here:
sealed abstract class Acceptable[T]
object Acceptable {
implicit object IntOk extends Acceptable[Int]
implicit object LongOk extends Acceptable[Long]
}
def f[T: Acceptable](t: T) = t
scala> f(1)
res0: Int = 1
scala> f(1L)
res1: Long = 1
scala> f(1.0)
<console>:8: error: could not find implicit value for parameter ev: Acceptable[Double]
f(1.0)
^
EDIT
This works if class and object are companions. On REPL, if you type each on a different line (ie, a "result" appears between them), they are not companions. You can type it like below, though:
scala> sealed abstract class Acceptable[T]; object Acceptable {
| implicit object IntOk extends Acceptable[Int]
| implicit object LongOk extends Acceptable[Long]
| }
defined class Acceptable
defined module Acceptable
You could get a little mileage from the Either type. However the Either hierarchy is sealed and handling more than two types becomes cumbersome.
scala> implicit def string2either(s: String) = Left(s)
string2either: (s: String)Left[String,Nothing]
scala> implicit def int2either(i: Int) = Right(i)
int2either: (i: Int)Right[Nothing,Int]
scala> type SorI = Either[String, Int]
defined type alias SorI
scala> def foo(a: SorI) {a match {
| case Left(v) => println("Got a "+v)
| case Right(v) => println("Got a "+v)
| }
| }
foo: (a: SorI)Unit
scala> def bar(a: List[SorI]) {
| a foreach foo
| }
bar: (a: List[SorI])Unit
scala>
scala> foo("Hello")
Got a Hello
scala> foo(10)
Got a 10
scala> bar(List(99, "beer"))
Got a 99
Got a beer
Another solution is wrapper classes:
case class IntList(l:List[Int])
case class StringList(l:List[String])
implicit def li2il(l:List[Int]) = IntList(l)
implicit def ls2sl(l:List[String]) = StringList(l)
def foo(list:IntList) = { println("Int-List " + list.l)}
def foo(list:StringList) = { println("String-List " + list.l)}
There is this hack:
implicit val x: Int = 0
def foo(a: List[Int])(implicit ignore: Int) { }
implicit val y = ""
def foo(a: List[String])(implicit ignore: String) { }
foo(1::2::Nil)
foo("a"::"b"::Nil)
See http://michid.wordpress.com/2010/06/14/working-around-type-erasure-ambiguities-scala/
And also this question.