- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Implicits + companion objects
Mon, 2010-04-12, 15:29
Just noticed this in trunk and 2.8.0-beta-prerelease:
test.scala
------------------------------
trait M[A]
trait TestImplicits {
implicit def makeM[A] = new M[A] {}
}
trait Test {
def foo[A : M](x : A) = println(implicitly[M[A]].getClass)
}
object Test extends TestImplicits
class Test2 extends Test
object Test2 extends TestImplicits
Console
------------------------------
jsuereth@jsuereth-laptop:~/projects/blog/implicit-subclass$ scalac subclass-test.scala
jsuereth@jsuereth-laptop:~/projects/blog/implicit-subclass$ scala -cp .
Welcome to Scala version 2.8.0.r21454-b20100411185142 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_15).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val x = new Test {}
x: java.lang.Object with Test = $anon$1@19a33662
scala> x.foo(5)
<console>:7: error: could not find implicit value for evidence parameter of type M[Int]
x.foo(5)
^
scala> val y = new Test2
y: Test2 = Test2@2161fcdd
scala> y.foo(5)
<console>:7: error: could not find implicit value for evidence parameter of type M[Int]
y.foo(5)
^
scala> import Test2
| ;
<console>:2: error: '.' expected but ';' found.
;
^
scala> import Test2._
import Test2._
scala> y.foo(5)
class TestImplicits$$anon$1
scala> x.foo(5)
class TestImplicits$$anon$1
I'm not sure exactly how to read the SLS spec, but I had assumed that the companion object of type T would be in the implicit scope... See Relevant portion of SLS in section 7.2
The implicit scope of a type T consists of all companion modules (§5.4) of classes
that are associated with the implicit parameter’s type. Here, we say a class C is associated
with a type T , if it is a base class (§5.1.2) of some part of T . The parts of a type
T are:
• if T is a compound type T1 with . . . with Tn, the union of the parts of
T1, . . . , Tn, as well as T itself,
• if T is a parameterized type S[T1, . . . , Tn], the union of the parts of S and
T1, . . . , Tn,
• if T is a singleton type p.type, the parts of the type of p,
• if T is a type projection S#U, the parts of S as well as T itself,
• in all other cases, just T itself.
Reading this, it made me assume that perhaps the implicits need to be defined on T itself (rather than its companion...). SO I tried the following:
scala> class Test3 extends Test with TestImplicits
defined class Test3
scala> val z = new Test3
z: Test3 = Test3@4a5afcb1
scala> z.foo(5)
<console>:8: error: could not find implicit value for evidence parameter of type M[Int]
z.foo(5)
As you can see, no dice. Is there something obvious I'm missing, or should I file a bug?
Thanks!
- Josh Suereth
test.scala
------------------------------
trait M[A]
trait TestImplicits {
implicit def makeM[A] = new M[A] {}
}
trait Test {
def foo[A : M](x : A) = println(implicitly[M[A]].getClass)
}
object Test extends TestImplicits
class Test2 extends Test
object Test2 extends TestImplicits
Console
------------------------------
jsuereth@jsuereth-laptop:~/projects/blog/implicit-subclass$ scalac subclass-test.scala
jsuereth@jsuereth-laptop:~/projects/blog/implicit-subclass$ scala -cp .
Welcome to Scala version 2.8.0.r21454-b20100411185142 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_15).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val x = new Test {}
x: java.lang.Object with Test = $anon$1@19a33662
scala> x.foo(5)
<console>:7: error: could not find implicit value for evidence parameter of type M[Int]
x.foo(5)
^
scala> val y = new Test2
y: Test2 = Test2@2161fcdd
scala> y.foo(5)
<console>:7: error: could not find implicit value for evidence parameter of type M[Int]
y.foo(5)
^
scala> import Test2
| ;
<console>:2: error: '.' expected but ';' found.
;
^
scala> import Test2._
import Test2._
scala> y.foo(5)
class TestImplicits$$anon$1
scala> x.foo(5)
class TestImplicits$$anon$1
I'm not sure exactly how to read the SLS spec, but I had assumed that the companion object of type T would be in the implicit scope... See Relevant portion of SLS in section 7.2
The implicit scope of a type T consists of all companion modules (§5.4) of classes
that are associated with the implicit parameter’s type. Here, we say a class C is associated
with a type T , if it is a base class (§5.1.2) of some part of T . The parts of a type
T are:
• if T is a compound type T1 with . . . with Tn, the union of the parts of
T1, . . . , Tn, as well as T itself,
• if T is a parameterized type S[T1, . . . , Tn], the union of the parts of S and
T1, . . . , Tn,
• if T is a singleton type p.type, the parts of the type of p,
• if T is a type projection S#U, the parts of S as well as T itself,
• in all other cases, just T itself.
Reading this, it made me assume that perhaps the implicits need to be defined on T itself (rather than its companion...). SO I tried the following:
scala> class Test3 extends Test with TestImplicits
defined class Test3
scala> val z = new Test3
z: Test3 = Test3@4a5afcb1
scala> z.foo(5)
<console>:8: error: could not find implicit value for evidence parameter of type M[Int]
z.foo(5)
As you can see, no dice. Is there something obvious I'm missing, or should I file a bug?
Thanks!
- Josh Suereth