Let's begin with a simple example.
scala> object holder {
| trait Foo {
| implicit val x = new Foo { override def toString = "trait foo" } }
| object Foo {
| implicit val y = new Foo { override def toString = "object foo" } }
| }
defined module holder
scala> import holder.Foo
import holder.Foo
scala> def method(implicit foo: Foo) = println(foo)
method: (implicit foo: holder.Foo)Unit
scala> method
java.lang.StackOverflowError
at holder$Foo$$anon$1.
at holder$Foo$class.$init$(
at holder$Foo$$anon$1.
at holder$Foo$class.$init$(
at holder$Foo$$anon$1.
at holder$Foo$class.$init$(
at holder$Foo$$anon$1.
at holder$Foo$class.$init$(
at holder$Foo$$anon$1.
at holder$Foo$class.$init$(
The interesting thing is that the Scala runtime can't seem to make up its mind whether to invoke the "x" or the "y" when its being looked up in the call to "method".
Another example would be related to Scala's package objects. To see how the problem can manifest itself, here's an example with a file named package.scala in Scala's convention and here are its contents:
package object foo {
implicit def foo = new Foo
implicit def foo2 = new Foo
}
package foo {
class Foo {
override def toString = "FOO!"
}
}
when you run the compilation via scalac, it generates a directory foo and dumps the class files there. Nothing to it. Now run scala and use the implicitly function and you'll see what i mean.
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_29).
Type in expressions to have them evaluated.
Type :help for more information.
scala> implicitly[foo.Foo]
both method foo in package foo of type => foo.Foo
and method foo2 in package foo of type => foo.Foo
match expected type foo.Foo
implicitly[foo.Foo]
The idea is to really limit the scope in which the implicits exist so as to reduce the amount of pain you have to go through when debugging
0 comments:
Post a Comment