Cannot find implicit value

Hi All.

Please pardon my ignorance (I am a bit new to Scala), but I am having this small problem that I am unable to solve. I have following code:

package test

sealed trait AType

trait ATypeLike[T] {
  def asAType(v: T): AType
}

object ATypeLike {
  def apply[T:ATypeLike]: ATypeLike[T] = implicitly

  implicit val s2a: ATypeLike[String] = new ATypeLike[String] {
    override def asAType(v: String): AType = v match {
      case "foo" => Foo
      case "boo" => Boo
      case _ => throw new IllegalArgumentException
    }
  }

  implicit val a2a: ATypeLike[AType] = new ATypeLike[AType] {
    override def asAType(v: AType): AType = v
  }
}

object Foo extends AType {
  override def toString: String = "FOO"
}

object Boo extends AType {
  override def toString: String = "BOO"
}

object TypeClassTest {
  def pprint[A: ATypeLike](v: A): String = {
    ATypeLike[A].asAType(v).toString
  }

  def main(args: Array[String]): Unit = {
    println(pprint("foo"))
    println(pprint(Foo))
  }
}

When trying to compile it I get following error:

Error:(40, 19) could not find implicit value for evidence parameter of type test.ATypeLike[test.Foo.type]
    println(pprint(Foo))

Could anyone point me at what I am doing wrong here?


Dmitri Priimak

Your expectation is that a2a will be picked, right? Here is the expanded signature of pprint.

def pprint[A](v: A)(implicit ev: ATypeLike[A]): String

Type parameter inference is done arglist by arglist. When you pass Foo, A is inferred to be Foo.type. The next (implicit) arglist is irrelevant to the typechecker at this point.

That means the implicit search is for ATypeLike[Foo.type]. a2a does not have this type.

One good way to solve this is to make a2a polymorphic.

implicit def a2a[A <: AType]: ATypeLike[A]

The other good way is to avoid using object to define Foo and Boo. You always get a subtype when you use object, which empirically has confused you at least once.

Making ATypeLike contravariant may seem simple and attractive, but will make more potential bugs possible. You should only consider this if your program design makes heavy use of subtyping.

I see. So are you saying that object Foo will create subtype and Foo will be of type Foo.type which is a subtype of AType, but if I do:

val Foo = new AType { }
val Boo = new AType { }

then these new variables will be of type AType?

Hello,

Just to be clear:

**Welcome to Scala 2.12.4 (OpenJDK 64-Bit Server VM, Java 1.8.0_151).
Type in expressions for evaluation. Or try :help.

class AType
defined class AType

val a1 = new AType
a1: AType = AType@221a2068

val a2 = new AType { }
a2: AType = $anon$1@5f366587**

The notation new AType creates an instance of AType, but the notation new AType { } creates both an anonymous subclass of AType and an instance of that anonymous subclass.

Best, Oliver

The short answer is: to be safe, write val Foo: AType = ... instead, and then for sure they will be of type AType. If you leave off the annotation and get it wrong, you’ll get an error like in your original post.

If you need access to properties of Foo that are not in AType, then you have a subtype, and you will want to go the polymorphic-a2a approach instead.

Let me know if you care to hear the long answer to your immediate question.