The first problem is that due to the way you work in REPL, the second foobar just obscures the first. If you want an overloaded definition, you will need to use :paste to define both at once.
This still will not give you what you want, just a new error message:
scala> println(foobar(new Foo)) <console>:14: error: ambiguous reference to overloaded definition, both method foobar of type [T](x: T)(implicit ev: EGT.<:!<[T,Foo])Int and method foobar of type [T](x: T)(implicit ev: <:<[T,Foo])String match argument types (Foo) and expected result type Any println(foobar(new Foo)) ^
(Note that I abbreviated ExtendedGenericTypes because I hate horizontal scrollbars.)
You can even try to explicitly specify an instance of <:< :
scala> foobar(new Foo)(implicitly[Foo <:< Foo]) <console>:14: error: ambiguous reference to overloaded definition, both method foobar of type [T](x: T)(implicit ev: EGT.<:!<[T,Foo])Int and method foobar of type [T](x: T)(implicit ev: <:<[T,Foo])String match argument types (Foo) foobar(new Foo)(implicitly[Foo <:< Foo]) ^
So what happens here is that the compiler will not allow the second list of parameters to determine which overloaded definition to use. This seems to mean that overloaded methods with multiple parameter lists, where the first parameter lists are the same, are essentially useless. Probably the ticket for this is the first glance I can think of, SI-2383 .
None of this matters, because you simply shouldn't use overloaded methods here. Overloading is a terrible "feature" that hangs from Java and breaks all kinds of stuff .
However, there are other possible approaches. Some of my favorite Scala weird tricks rely on the fact that you can provide a default value for an implicit parameter that will be used if the compiler cannot find the instance. If I understand correctly, you want something like this:
class Foo def foobar[T](x: T)(implicit ev: T <:< Foo = null) = Option(ev).fold[Either[Int, String]](Left(5))(_ => Right("hello")) case class Bar(i: Int) extends Foo case class Baz(i: Int)
And then:
scala> foobar(Bar(13)) res0: Either[Int,String] = Right(hello) scala> foobar(Baz(13)) res1: Either[Int,String] = Left(5)
Note that I am using Either instead of allowing the existence of an implicit definition of the return type. There are ways in which you could do this (for example, Shapeless first- the values โโof the polymorphic functions of a class ), but in this case they are likely to be excessive.
Update: good, since you asked for it:
import shapeless._ trait LowPriorityFoobar { this: Poly1 => implicit def anyOld[T] = at[T](_ => 5) } object foobar extends Poly1 with LowPriorityFoobar { implicit def foo[T](implicit ev: T <:< Foo) = at[T](_ => "hello") }
And then:
scala> foobar(Bar(13)) res6: String = hello scala> foobar(Baz(13)) res7: Int = 5
No wrapper. You must think very hard before taking this approach.
Update to update, for completeness: you can also do it more directly (but also in more detail) without Shapeless using dependent types of methods (again, you will need to use :paste to define all this at once):
class Foo trait IsFooMapper[I] { type Out def apply(i: I): Out } trait LowPriorityIsFooMapper { implicit def isntFoo[A] = new IsFooMapper[A] { type Out = Int def apply(a: A) = 5 } } object IsFooMapper extends LowPriorityIsFooMapper { implicit def isFoo[A](implicit ev: A <:< Foo) = new IsFooMapper[A] { type Out = String def apply(a: A) = "hello" } } def foobar[A](a: A)(implicit ifm: IsFooMapper[A]) = ifm(a)
And then:
scala> foobar(Bar(13)) res0: String = hello scala> foobar(Baz(13)) res1: Int = 5
Again, this is a fairly advanced material and should be used with caution.