3
votes

In the following code snippet (using scala 2.10.3) TestClass1 does not compile with error "value toInt is not a member of String" but TestClass2 compiles fine:

trait TestTrait {
  implicit def test: (String => Int)
}

object TestClass1 extends TestTrait {
  implicit val test = (value: String) => value.toInt
}

object TestClass2 extends TestTrait {
  implicit def test = (value: String) => value.toInt
}

The StringOps implicit conversion via augmentString(), which provides the toInt function, is not applied in TestClass1 but is applied fine in TestClass2. Can somebody tell me why this is the case and how to keep test a val instead of a def?

1
val is only evaluated once during lifetime of your TestClass1 object, therefore it can't have arbitrary arguments. If value was a member of your TestClass1 object, you could make it work : object TestClass1 (value:String) { implicit val test => value.toInt } but that's probably not what you had in mind?Ashalynd
That would only work with classes not objects, right? I'm definitely interested in using an object.Kevin Schmidt
As far as I know, it holds for objects too.Ashalynd

1 Answers

2
votes

This is a limitation of implicit definitions when the return type needs to inferred, I think. You are in a somewhat similar situation as defining a recursive method. That is to say, the "open" implicit definition triggers implicit lookup in its body, which in theory could be recursive. (At least that's my explanation of this limitation).

You can either annotate the type:

object TestClass1 extends TestTrait {
  implicit val test: String => Int = value => value.toInt  // or _.toInt
}

or remove the implicit keyword—since it is implementing the implicit method from TestTrait, you do not need to re-state the implicit keyword:

object TestClass1 extends TestTrait {
  val test = (value: String) => value.toInt
}