I have the following code:
case class Number (value:Int)
and
class Calculator {
def performCalc( input:Number)(implicit calc: (Number=>Number) ) = calc(input)
}
Now, when I, in a specs2 test try this:
class CalculatorTest extends mutable.Specification {
"Calculator" should {
"* Accept explicit calculation parameter" in {
implicit val addTwelve = (input: Number) => Number(input.value + 12)
val calc = new Calculator()
val result = calc.performCalc(Number(4))
result must beEqualTo(16)
}
}
}
I expected the 'addTwelve' function to be injected implicitly as a parameter of performCalc. However, I get the following failure:
Error:(49, 42) ambiguous implicit values:
both method $conforms in object Predef of type [A]=> <:<[A,A]
and value addTwelve of type nl.example.Number => nl.example.Number
match expected type nl.example.Number => nl.example.Number
val result = calc.performCalc(Number(4))
^
What am I doing wrong? It should be possible to use methods as implicits, right?
Scala: 2.11.7
Yes this is technically a valid use of implicit, but it's not a very strong use case. Specifically, there is a pre-existing implicit that provides Number=>Number. The compiler is having trouble telling which implicit method you really want.
What's better is to wrap this method into a trait as a "tag" for the implicit type.
case class Number(value: Int)
trait CalcMethod {
def perform(n: Number): Number
}
class Calculator {
def performCalc(input:Number)(implicit calc: CalcMethod) = calc.perform(input)
}
class CalculatorTest extends mutable.Specification {
"Calculator" should {
"* Accept explicit calculation parameter" in {
implicit val addTwelve: CalcMethod = new CalcMethod {
def perform(input: Number) = Number(input.value + 12)
}
val result = new Calculator().performCalc(Number(4))
result must beEqualTo(16)
}
}
}
EDIT:
This is maybe closer to what you want:
case class Number(value: Int)
implicit class CalcMethod(val perform: Number => Number)
class Calculator {
def performCalc(input:Number)(implicit calc: CalcMethod) = calc.perform(input)
}
Then you can use it like so:
implicit val addTwelve: CalcMethod = (input: Number) => Number(input.value + 12)
val result = new Calculator().performCalc(Number(4))