lisak
lisak

Reputation: 21961

Unable to resolve path dependent type class evidence w/o having value type accessible

I got stuck for like an hour to discover this fact:

class Foo {
  trait TypeClass[X]
  object TypeClass {
    implicit val gimme = new TypeClass[Int]{}
  }

  def foo[X : TypeClass](p: X): Unit = println("yeah " + p)
}

    // compiles
val foo = new Foo()
foo.foo(4)

    //does not compile
new Foo().foo(4)

    could not find implicit value for evidence parameter of type _1.TypeClass[Int]
    [error]   new Foo().foo(4)
    [error]    

I can't figure out why that is. The only thing that I can think of is that scalac doesn't find implicits within a Type that doesn't have a Value Type accessible on any prefix. It cannot be referenced. Scalac apparently needs to access that Foo.this.foo to resolve implicits in it, which it can't in this case.

I feel like that if you combine type classes and path dependent types, you are effectively doomed. You'll end up dealing with this kind of stuff. I did that because scalac wouldn't otherwise infer types in my API methods and user would have to declare them explicitly. So I chose this kind of design so that types are constructed in Foo[T] and api methods use the existing type, but I hit several really ugly problems and bugs of this kind that made my app look like an overengineered crap...

Upvotes: 4

Views: 181

Answers (1)

dk14
dk14

Reputation: 22374

Path dependent types may be bound only to some stable immutable values, so the more obvious example also will not work, because immutability is not guaranteed:

scala> var foo = new Foo()
foo: Foo = Foo@4bc814ba

scala> foo.foo(4)
<console>:17: error: could not find implicit value for evidence parameter of type    _37.TypeClass[Int]
          foo.foo(4)
                 ^

scala> def foo = new Foo()
foo: Foo

scala> foo.foo(4)
<console>:17: error: could not find implicit value for evidence parameter of type _39.TypeClass[Int]
          foo.foo(4)
                 ^

_37 means that type was not inferred. So, it seems like scala simply infer type only after it's assigned to some val. It's not related to implicits actually, this will give you the more clear explanation:

scala> class C {type K = Int}
defined class C

scala> var z = new C
z: C = C@4d151931

scala> def aaa(a: z.K) = a
<console>:16: error: stable identifier required, but z found.
   def aaa(a: z.K) = a
              ^

scala> def z = new C
z: C

scala> def aaa(a: z.K) = a
<console>:16: error: stable identifier required, but z found.
   def aaa(a: z.K) = a
              ^

Your new Foo expression is similar to def newFoo = new Foo, so there it's considered as unstable.

Upvotes: 4

Related Questions