Reputation: 21961
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
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