Reputation: 49
Why is the implicit not being picked up automatically?? implicit class is not picked up by default as evidence in the code below.
object temp {
def main(args: Array[String]): Unit = {
case class Foo(str: String)
trait Special[A] {
def getStr: String
}
implicit class SpecialFoo(x: Foo) extends Special[Foo] {
def getStr = x.str
}
/* For the above SpecialFoo implicit class, I think the following is replaced by the compiler:
* --------------------------------------------------------------------------------------------
class SpecialFooClass(x: Foo) {
def getStr: String = x.str
}
implicit def specialFooFunction(x: Foo): SpecialFooClass = new SpecialFooClass(x);
* --------------------------------------------------------------------------------------------
*/
def specialFunction[T: Special](thing: T): String = implicitly[Special[T]].getStr;
// val wrapped = specialFunction(Foo("hi")) // Will not pick up the implicit SpecialFoo class, why??
val foo = Foo("hi")
val wrapped1: String = specialFunction(foo)(SpecialFoo(foo)) // But giving the evidence explicitly works!
println(wrapped1)
}
}
Upvotes: 1
Views: 286
Reputation: 5093
Although @francoisr answer is a valid answer it seems like you would like to be able to pass an object to a method that implements Special[A]
interface. Your code will compile for the following definition of specialFunction
.
def specialFunction[T](thing: T)(implicit toSpecial: T => Special[T]): String = thing.getStr
This expresses your need to convert type T
to a Special[T]
and thus you are able to call .getStr
method.
Upvotes: 2
Reputation: 4595
It looks like you're mixing up two concepts here.
On one hand, there is implicit conversion, which means the compiler will convert a value of type Foo
into a value of type Special[Foo]
whenever it needs to. That's indeed what your implicit class
declares.
On the other hand, the
def specialFunction[T: Special](thing: T): String
is a shortcut for
def specialFunction[T](thing: T)(implicit ev: Special[T]): String
This means the specialFunction
method takes two arguments. The second argument is implicit, which means that if you don't pass it explicitly, the compiler will try to find it in the implicit scope. However, here you don't have an implicit Special[Foo]
in scope. What you have is an implicit way to convert Foo
into Special[Foo]
.
The pattern you're trying to use here is very common, but it's usually achieved in another way:
trait Special[A] {
def getStr(a: A): String
}
case class Foo(str: String)
object Foo {
implicit val special: Special[Foo] = new Special[Foo] {
override def getStr(a: Foo) = a.str
}
}
def specialFunction[T: Special](thing: T): String =
implicitly[Special[T]].getStr(thing)
val foo = Foo("hi")
println(specialFunction(foo))
Here, we don't wrap Foo
into Special[Foo]
, but instead treat Special[A]
as a separate entity that knows how to extract a String
from an A
.
Note: If you're using Scala 2.12, you can express val special
in a very concise way thanks to support for single abstract method (traits or abstract classes that only consist of a single abstract method, like Special[A]
only has getStr
):
implicit val special: Special[Foo] = _.str
Upvotes: 2