4

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...

lisak
  • 21,611
  • 40
  • 152
  • 243

1 Answers1

4

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.

dk14
  • 22,206
  • 4
  • 51
  • 88
  • so the last snippet of mine has an immutable identifier that is not stable because it is in a method scope, so that doesn't work either? ` def method() = { // this doesn't compile either if it is within a method scope val foo = new Foo() foo.foo[Int](4) }' – lisak Dec 21 '14 at 18:39
  • actually last snippet works for me - Scala REPL 2.11.2 – dk14 Dec 21 '14 at 18:44
  • I also declared it inside of object (see update in my answer) and ran/compiled using scala/scalac - and it works – dk14 Dec 21 '14 at 18:52
  • But here you declared implicit val inside class itself - implicits doesn't work that way (they should be defined inside companion object), see http://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html. Or just `import foo._` – dk14 Dec 21 '14 at 18:56
  • Ups, I forgot it this way when I was playing with it, sorry... Thank you dk14, you got it. – lisak Dec 21 '14 at 18:57