Problem
Given a simple class hierarchy
abstract class Base {}
class A extends Base {}
class B extends Base {}
And a typeclass
trait Show[T] {
def show(obj: T): String
}
With overloaded implementations
class ShowBase extends Show[Base] {
override def show(obj: Base): String = "Base"
}
object ShowA extends ShowBase {
def show(obj: A): String = "A"
}
object ShowB extends ShowBase {
def show(obj: B): String = "B"
}
When executing following test-case
Seq((new A(), ShowA), (new B(), ShowB)).foreach {
case (obj, showImpl) => println(showImpl.show(obj), obj.getClass.getSimpleName)
}
Should produce (A,A) \n (B,B), but produces (Base,A) \n (Base,B) instead.
Question
What's going on here? Shouldn't the method with the most specific runtime type be called - Polymorphism 101?
This issue looks similar to another question where a type parameter prevents the correct resolution of which method to call. However, in my case the type parameterized show method is provided with actual implementations in contrast to type parameterized method in the other question.
Naive solution
Extending the ShowA implementation (analogue for ShowB):
object ShowA extends ShowBase {
def show(obj: A): String = "A"
override def show(obj: Base): String = {
require(obj.isInstanceOf[A], "Argument must be instance of A!")
show(obj.asInstanceOf[A])
}
}
gives the expected output. The problem is mixing A with ShowB will result in an exception.
Static overload resolution is easy to reason about: for the methods that are applicable, a method is selected as "more specific" just based on the signatures.
However,
scala> Seq((new A(), ShowA), (new B(), ShowB))
res0: Seq[(Base, ShowBase)] = List((A#2b45f918,ShowA$#7ee4acd9), (B#57101ba4,ShowB$#6286d8a3))
in ShowBase there is no overload.
scala> res0 foreach {
| case (obj: A, showImpl) => println(showImpl.show(obj), obj.getClass.getSimpleName)
| case (obj: B, showImpl) => println(showImpl.show(obj), obj.getClass.getSimpleName)
| }
java.lang.InternalError: Malformed class name
at java.lang.Class.getSimpleName(Class.java:1180)
at $anonfun$1.apply(<console>:17)
at $anonfun$1.apply(<console>:16)
at scala.collection.immutable.List.foreach(List.scala:383)
... 38 elided
Oh yeah, don't use getSimpleName from Scala.
scala> res0 foreach {
| case (obj: A, showImpl) => println(showImpl.show(obj), obj.getClass)
| case (obj: B, showImpl) => println(showImpl.show(obj), obj.getClass) }
(Base,class $line4.$read$$iw$$iw$A)
(Base,class $line5.$read$$iw$$iw$B)
OTOH,
scala> class ShowBase extends Show[Base] {
| override def show(obj: Base): String = "Base"
| def show(a: A) = "A" ; def show(b: B) = "B" }
defined class ShowBase
scala> Seq((new A(), new ShowBase), (new B(), new ShowBase))
res3: Seq[(Base, ShowBase)] = List((A#15c3e01a,ShowBase#6eadd61f), (B#56c4c5fd,ShowBase#10a2918c))
scala> res3 foreach {
| case (obj: A, showImpl) => println(showImpl.show(obj), obj.getClass)
| case (obj: B, showImpl) => println(showImpl.show(obj), obj.getClass) }
(A,class $line4.$read$$iw$$iw$A)
(B,class $line5.$read$$iw$$iw$B)
It's easy to imagine a macro that generates the partial function for a given interface with an overloaded method show.
Another idea, not necessarily a great one, is to let the compiler do the selection at runtime.
This is currently awkward to demonstrate in REPL. You have to import any symbols you want to use from the objects that litter your REPL history. See the issue.
scala> def imps = $intp.definedSymbolList map (s => $intp.global.exitingTyper { s.fullName }) mkString ("import ", "\nimport ", "\n")
imps: String
scala> tb.eval(tb.parse(s"$imps ; ShowA show a"))
res15: Any = A
Hey, it worked!
Or, go into power mode, which sets the current phase at typer and gives you intp without the funky dollar sign. Because do we really need more dollars?
scala> :power
** Power User mode enabled - BEEP WHIR GYVE **
** :phase has been set to 'typer'. **
** scala.tools.nsc._ has been imported **
** global._, definitions._ also imported **
** Try :help, :vals, power.<tab> **
scala> def imps = intp.definedSymbolList map (_.fullName) mkString ("import ", "\nimport ", "\n")
imps: String
scala> tb.eval(tb.parse(s"$imps ; ShowA show a"))
res17: Any = A
If you want to see your unsanitized imports:
scala> intp.isettings.unwrapStrings = false
intp.isettings.unwrapStrings: Boolean = false
scala> imps
res11: String =
"import $line2.$read.$iw.$iw.$intp
import $line3.$read.$iw.$iw.Base
import $line3.$read.$iw.$iw.A
import $line3.$read.$iw.$iw.B
import $line4.$read.$iw.$iw.Show
import $line5.$read.$iw.$iw.ShowA
[snip]
Once more:
scala> abstract class Base ; class A extends Base ; class B extends Base
defined class Base
defined class A
defined class B
scala> trait Show[T <: Base] { def show(obj: T): String }
defined trait Show
scala> class ShowBase extends Show[Base] { override def show(obj: Base): String = "Base" }
defined class ShowBase
scala> object ShowA extends ShowBase { def show(obj: A): String = "A" }
defined object ShowA
scala> :power
** Power User mode enabled - BEEP WHIR GYVE **
** :phase has been set to 'typer'. **
** scala.tools.nsc._ has been imported **
** global._, definitions._ also imported **
** Try :help, :vals, power.<tab> **
scala> def imps = intp.definedSymbolList map (_.fullName) mkString ("import ", "\nimport ", "\n")
imps: String
scala> import tools.reflect._
import tools.reflect._
scala> val tb = reflect.runtime.currentMirror.mkToolBox()
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl#24e15d95
Did I mention the import mechanism is awkward?
scala> val a = new A
a: A = A#1e5b2860
scala> tb.eval(tb.parse(s"$imps ; ShowA show a"))
res0: Any = A
scala> ShowA show (a: Base)
res1: String = Base
scala> tb.eval(tb.parse(s"$imps ; ShowA show (a: Base)"))
res2: Any = Base
scala> val a: Base = new A
a: Base = A#7e3a93ce
scala> tb.eval(tb.parse(s"$imps ; ShowA show a"))
scala.tools.reflect.ToolBoxError: reflective compilation has failed:
reference to a is ambiguous;
it is imported twice in the same scope by
import a
and import a
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.throwIfErrors(ToolBoxFactory.scala:315)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.wrapInPackageAndCompile(ToolBoxFactory.scala:197)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.compile(ToolBoxFactory.scala:251)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$$anonfun$compile$2.apply(ToolBoxFactory.scala:428)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$$anonfun$compile$2.apply(ToolBoxFactory.scala:421)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.liftedTree2$1(ToolBoxFactory.scala:354)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.apply(ToolBoxFactory.scala:354)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.compile(ToolBoxFactory.scala:421)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.eval(ToolBoxFactory.scala:443)
... 37 elided
So, if you decide what type you want to select on:
scala> val x: Base = new A
x: Base = A#2647e550
scala> tb.eval(tb.parse(s"$imps ; ShowA show x"))
res4: Any = Base
scala> tb.eval(tb.parse(s"$imps ; ShowA show (x.asInstanceOf[A])"))
res5: Any = A
It's not an answer to your question, looks more like a workaround:
abstract class Base {}
class A extends Base {}
class B extends Base {}
trait Show[T] {
def show(obj: T): String
}
class ShowBase extends Show[Base] {
override def show(obj: Base): String = "Base"
}
object ShowA extends Show[A] {
override def show(obj: A): String = "A"
}
object ShowB extends Show[B] {
override def show(obj: B): String = "B"
}
case class ^[T <: Base](obj: T, show: Show[T])
Seq(^(new A(), ShowA), ^(new B(), ShowB)).foreach {
case ^(obj, showImpl) => println(showImpl.show(obj), obj.getClass.getSimpleName)
}
I had a fundamental error in thinking that overloaded methods are called based on dynamic binding (If you are wondering, the experience was like discovering that 2+2 is 5 instead of 4).
Thanks to som-snytt's answer and to a blog post about static and dynamic binding in Java I figured out that that is not the case. Overloaded methods are called based on static types. Overridden methods are called based on dynamic types. Hence the problem in my original question is based on static binding: som-snytt's answer explains that in more detail.
Related
I want to do something like this:
def fold[C[A]](implicit ev: Foldable[A]): A
I am getting not found: type A
I know, I can do this instead:
def fold[C[_], A: Foldable]: A
But, I would rather invoke as fold[List[Int]] than fold[List, Int]
I played a bit with it and came up with a helper type class:
trait Helper[M[_], CA] {
type C[_]
type A
implicit def ma: M[A]
}
object Helper {
implicit def instance[M0[_], C0[_], A0](implicit ma0: M0[A0]) = new Helper[M0, C0[A0]] {
type C[X] = C0[X]
type A = A0
val ma: M0[A0] = ma0
}
}
I know the names are pretty generic, I'd suggest finding more meaningful names.
Now instead of requiring an implicit of type Foldable[A] you require instead an implicit of Helper[Foldable, CA] where CA is the type that must match against List[Int] in your example:
def fold[CA](implicit helper: Helper[Foldable, CA]): helper.A
As an example:
def fold[CA](implicit helper: Helper[Foldable, CA]): helper.A = {
import helper._
println(implicitly[Foldable[A]])
null.asInstanceOf[A]
}
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class Foldable[A](name: String)
implicit val stringFoldable = Foldable[String]("String")
implicit val intFoldable = Foldable[Int]("Int")
implicit val floatFoldable = Foldable[Float]("Float")
def fold[CA](implicit helper: Helper[Foldable, CA]): helper.A = {
import helper._
println(implicitly[Foldable[A]])
null.asInstanceOf[A]
}
// Exiting paste mode, now interpreting.
defined class Foldable
stringFoldable: Foldable[String] = Foldable(String)
intFoldable: Foldable[Int] = Foldable(Int)
floatFoldable: Foldable[Float] = Foldable(Float)
fold: [CA](implicit helper: Helper[Foldable,CA])helper.A
scala> fold[List[String]]
Foldable(String)
res0: String = null
scala> fold[List[Int]]
Foldable(Int)
res1: Int = 0
scala> fold[List[Float]]
Foldable(Float)
res2: Float = 0.0
Here's what I came up with:
trait Foo[T, A]
implicit def makeFoo[A, M[_]] = new Foo[M[A], A] {}
class Helper[T] {
def apply[A]()(implicit ev: Foo[T, A]) = ev
}
def bar[T] = new Helper[T]
bar[List[Int]]()
//Foo[List[Int],Int] = $anon$1#7edf6563
The empty pair of parens might not be ideal if you really want an a no-arg method, but I can't see how to get around that at the moment.
I'm working on a little generic tool, in which I need to have something like this:
An Operator trait, which will provide tools for operating elements
A Publisher trait, responsible for publishing a result represented by a Set() in the following example
A class which will implement operation traits
A companion object for this class, who will implement the publisher operations. It is mandatory for my design to keep the published results in the same trait as the publish operations
In a nutshell, I've got the following structure:
trait Publisher[A]{
var storage: Set[A] = Set[A]()
def publishOper(elem: A) = storage += elem
}
trait Operator[A, B]{
def operate(elem: A): B = ???
}
object Oper extends Publisher {
}
class Oper[A, B] extends Operator[A, B]{
def publishOper(elem: A): B = {
val res = operate(elem)
publishOper(res)
}
}
But, as you can imagine, I get the following error:
publishOper(res): Type mismatch, expected: A, actual: B
This raises several questions for me:
How does type inference work when extending a companion object? (aka: Why does this happen?)
How can I solve this, while trying to keep the same structure?
Use a shared publisher object, perhaps via an implicit. This is actually a bit more versatile as you can control scope now. Also this is testable, using the companion object as a singleton is likely not.
implicit operPub = new Publisher[B] {
// implementation...
}
class Oper[A, B](implicit publisher: Publisher[B]) extends Operator[A, B]{
def publishOper(elem: A): B = {
val res = operate(elem)
publishOper(res)
}
}
val a = new Oper[Int, String]
val b = new Oper[Int, String] // they both should get operPub
Global publisher is a bad idea as it will be non-typed then. But if you really need it - just don't bind your publisher to the concrete type:
object Oper extends Publisher[Any]
class Oper[A, B] extends Operator[A, B]{
def publishOper(elem: A): B = {
val res = operate(elem)
Oper.publishOper(res)
res
}
}
But this is a bad design. I'd recommend to define Oper as trait with external dependency:
trait Publisher[-A]{ //"-" - if can store Any then can store Int
type T >: A //to compensate covariant position for set or any other your internal providers; implementations without explicit T will produce existential type `_ >: A` for T to guarantee that storage will have a biggest A type
var storage: Set[T] = Set[T]()
def publishOper(elem: A) = storage += elem
}
trait Operator[A, B]{
def operate(elem: A): B = elem.asInstanceOf[B] //just mock
}
trait Oper[A, B] extends Operator[A, B]{
def publisher: Publisher[B]
def publishOper(elem: A): B = {
val res = operate(elem)
publisher.publishOper(res)
res
}
}
Example:
scala> val pbl = new Publisher[Any]{}
pbl: Publisher[Any] = $anon$1#49dbe5f0
scala> class Oper1 extends Oper[Int, Int] { val publisher: Publisher[Int] = pbl }
defined class Oper1
scala> new Oper1
res10: Oper1 = Oper1#4bd282fd
scala> res10.publishOper(3)
res11: Int = 3
scala> res10.publishOper(4)
res12: Int = 4
scala> res10.publisher.storage
res13: Set[res10.publisher.T] = Set(3, 4)
scala> class Oper2 extends Oper[Double, Double] { val publisher: Publisher[Double] = pbl }
defined class Oper2
scala> new Oper2
res14: Oper2 = Oper2#271f68d2
scala> res14.publishOper(2.0)
res15: Double = 2.0
scala> res14.publishOper(3.0)
res16: Double = 3.0
scala> res14.publisher.storage
res17: Set[res14.publisher.T] = Set(3, 4, 2.0)
So now, depending on your context - you can choose the biggest type, that your publisher may work with (in my example it was Any). The compiler will automatically check if it's fine with your Oper - that's why we need contravariant Publisher here.
P.S. Interesting note: 3.0 was casted to 3 automatically as expected existential type of collection was Int, so for my example there is no duplication Set(3,4, 2.0, 3.0) but strings of course will be different: Set(3, 4, 2.0, "3"):
scala> class Oper3 extends Oper[String, String] { val publisher = pbl }
defined class Oper3
scala> new Oper3
res23: Oper3 = Oper3#f93893c
scala> res23.publishOper("3")
res38: String = 3
scala> res23.publisher.storage
res39: Set[res23.publisher.T] = Set(3.0, 4.0, 2.0, 3)
I have createOld method that I need to override and I cannot change it. I would like to use TypeTag to pattern match provided type in createNew. The goal is to find out how to call createNew from createOld. My current understanding is that compiler doesn't have enough type information about A in createOld method if it doesn't already come with TypeTag[A].
object TypeTagFromClass {
class C1
class C2
// How to get TypeTag[A] needed by createNew?
def createOld[A](c: Class[A]): A = createNew ???
def createNew[A : TypeTag]: A = {
val result = typeOf[A] match {
case a if a =:= typeOf[C1] => new C1()
case a if a =:= typeOf[C2] => new C2()
}
result.asInstanceOf[A]
}
}
It is possible to create a TypeTag from a Class using Scala reflection, though I'm not sure if this implementation of TypeCreator is absolutely correct:
import scala.reflect.runtime.universe._
def createOld[A](c: Class[A]): A = createNew {
val mirror = runtimeMirror(c.getClassLoader) // obtain runtime mirror
val sym = mirror.staticClass(c.getName) // obtain class symbol for `c`
val tpe = sym.selfType // obtain type object for `c`
// create a type tag which contains above type object
TypeTag(mirror, new TypeCreator {
def apply[U <: Universe with Singleton](m: api.Mirror[U]) =
if (m eq mirror) tpe.asInstanceOf[U # Type]
else throw new IllegalArgumentException(s"Type tag defined in $mirror cannot be migrated to other mirrors.")
})
}
However, you don't really need full TypeTag if you don't need to inspect generic parameters and full Scala type information. You can use ClassTags for that:
def createNew[A: ClassTag]: A = {
val result = classTag[A].runtimeClass match {
case a if a.isAssignableFrom(classOf[C1]) => new C1()
case a if a.isAssignableFrom(classOf[C2]) => new C2()
}
result.asInstanceOf[A]
}
Or with some implicit sugar:
implicit class ClassTagOps[T](val classTag: ClassTag[T]) extends AnyVal {
def <<:(other: ClassTag[_]) = classTag.runtimeClass.isAssignableFrom(other.runtimeClass)
}
def createNew[A: ClassTag]: A = {
val result = classTag[A] match {
case a if a <<: classTag[C1] => new C1()
case a if a <<: classTag[C2] => new C2()
}
result.asInstanceOf[A]
}
You can simplify that even further by using plain old Java newInstance() method:
def createNew[A: ClassTag]: A = classTag[A].runtimeClass.newInstance().asInstanceOf[A]
This, of course, would only work if you don't need different constructor parameters for different classes.
Calling this createNew from createOld is much simpler than the one with TypeTags:
def createOld[A](c: Class[A]): A = createNew(ClassTag[A](c))
So it is not very safe and correct (cause you don't use the power of scala type system), but you can make (using your logic) to do the following:
def createNew[A](implicit t: TypeTag[A]): A = {
val result: Any = t.tpe.toString match {
case "C1" => new C1
case "C2" => new C2
}
result.asInstanceOf[A]
}
createNew[C1] //> its all ok
createNew[C2] //> its all ok
createNew[C3] //> crashes here; lets pretend we got C3 class
To use it with createOld, just pass implicit argument:
def createOld[A](c: Class[A])(implicit t: TypeTag[A]): A = createNew[A]
createOld[C1] //> its all ok
createOld[C2] //> its all ok
createOld[C3] //> crashes here; lets pretend we got C3 class
I think I should not tell you twice that it is not very good.
We can improve this code by using shapeless:
Lets create a poly function, which has a TypeTag as an argument:
import shapeless._; import scala.reflect.runtime.universe._;
def getTypeTag[T](implicit t: TypeTag[T]) = t //> to get TypeTag of a class
// here is low prority implicit
trait createPolyNewErr extends Poly1 {
implicit def newErr[T] = at[T](_ => "Error can not create object of this class")
}
object createPolyBew extends createPolyNewError {
implicit def newC1 = at[TypeTag[C1]](_ => new C1)
implicit def newC2 = at[TypeTag[C2]](_ => new C2)
}
createPolyNew(getTypeTag[C1]) //> success
createPolyNew(getTypeTag[C2]) //> success
createPolyNew(getTypeTag[C3]) //> String: Error can not create object of this class no crash!
We also can write a function, in order not to use function getTypeTag[T] every time:
def createPoly[T]
(implicit t: TypeTag[T],
cse: poly.Case[createPolyNew.type, TypeTag[T] :: HNil]) = cse(t)
createPoly[C1] //> its all ok
createPoly[C2] //> its all ok
createPoly[C3] //> String: Error can not create object of this class no crash!
I'm aware that case class inheritance is deprecated in Scala, but for the sake of simplicity, I've used it in the following example:
scala> case class Foo(val f: String) { def foo(g: String): Foo = { this.copy(f=g) }}
defined class Foo
scala> case class Bar(override val f: String) extends Foo(f)
warning: there were 1 deprecation warnings; re-run with -deprecation for details
defined class Bar
scala> Bar("F")
res0: Bar = Foo(F)
scala> res0.foo("G")
res1: Foo = Foo(G)
So far, so good. What I really want, though, is to be able to write a method foo() in Foo that returns an object of type Bar when called on an object of type Bar, without having to reimplement the method in class Bar. Is there a way to do this in Scala?
builder approach
Yes, it can be done. A good example of that is the collections library.
scala> List(1, 2, 3) take 2
res1: List[Int] = List(1, 2)
scala> Array(1, 2, 3) take 2
res2: Array[Int] = Array(1, 2)
See The Architecture of Scala Collections to see how it was done.
Edit:
It uses two approaches to reuse implementations. The first is by using common traits and builders, and the other is using type classes.
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait Builder[A] {
def apply(f: String): A
}
trait FooLike[A] {
def builder: Builder[A]
def f: String
def genericCopy(f: String): A = builder(f)
def map(fun: String => String): A = builder(fun(f))
}
case class Foo(f: String) extends FooLike[Foo] {
def builder = new Builder[Foo] {
def apply(f: String): Foo = Foo(f)
}
}
case class Bar(f: String) extends FooLike[Bar] {
def builder = new Builder[Bar] {
def apply(f: String): Bar = Bar(f)
}
}
scala> Foo("foo").genericCopy("something")
res0: Foo = Foo(something)
scala> Bar("bar").genericCopy("something")
res1: Bar = Bar(something)
scala> Foo("foo") map { _ + "!" }
res2: Foo = Foo(foo!)
The whole point of doing this, is so you can do something interesting at the common trait, like implementing common map in FooLike. It's hard to see the benefits with trivial code.
type class approach
The benefit of using a type class is that you can add features to Foo and Bar even when you can't change them (like String).
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class Foo(f: String)
case class Bar(f: String)
trait CanCopy[A] {
def apply(self: A, f: String): A
def f(self: A): String
}
object CanCopy {
implicit val fooCanCopy = new CanCopy[Foo] {
def apply(v: Foo, f: String): Foo = v.copy(f = f)
def f(v: Foo) = v.f
}
implicit val barCanCopy = new CanCopy[Bar] {
def apply(v: Bar, f: String): Bar = v.copy(f = f)
def f(v: Bar) = v.f
}
implicit val stringCanCopy = new CanCopy[String] {
def apply(v: String, f: String): String = f
def f(v: String) = v
}
def copy[A : CanCopy](v: A, f: String) = {
val can = implicitly[CanCopy[A]]
can(v, f)
}
def f[A : CanCopy](v: A) = implicitly[CanCopy[A]].f(v)
}
scala> CanCopy.copy(Foo("foo"), "something")
res1: Foo = Foo(something)
scala> CanCopy.f(Foo("foo"))
res2: String = foo
scala> CanCopy.copy(Bar("bar"), "something")
res3: Bar = Bar(something)
scala> CanCopy.copy("string", "something")
res4: java.lang.String = something
The copy method is implemented by the compiler and it does not seem to belong a common trait. The easiest way to do it is to define a trait:
trait HasFoo[T] {
def foo(g:String): T
}
case class Foo( f: String ) extends HasFoo[Foo] {
def foo( g: String ) = copy(f=g)
}
case class Bar( f: String ) extends HasFoo[Bar] {
def foo( g: String ) = copy(f=g)
}
scala> Bar("a").foo("b")
res7: Bar = Bar(b)
scala> Foo("a").foo("b")
res8: Foo = Foo(b)
Another option is to use type classes to provide an appropriate builder. But it wont save the number of typed characters.
Note: This does not create a new object but re-uses the this object. For general use, see paradigmatic’s answer.
For some reason, it does not work together with the case class’s copy method. (But admittedly, since case class inheritance should not be done anyway, the problem does not occur.). But for any other method, you do it with this.type.
case class Foo(val f: String) { def foo(g: String): this.type = { this }}
case class Bar(override val f: String) extends Foo(f)
Bar("F").foo("G")
res: Bar = Foo(F)
If you need the self-type variance in method arguments and method bodys (as opposed to return-type-only variance), you will need to go one step further and define
trait HasFoo[T <: HasFoo[T]] { this: T =>
def foo(g:String): T
def bar(g: T): T // here may follow an implementation
}
This will allow you to add proper method bodies to the trait. (See: proper class hierarchy for 2D and 3D vectors)
This solution doesn't require a separate trait.
class Bar
class Foo {
def returnMyType[A](x:A) :A = { println(x); x }
}
val f = new Foo
val b = new Bar
val bReturned = f.returnMyType(b)
println(bReturned.getClass.getName)
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.