Question

Why would this code not take the implicit functions defined in the local scope? From where else does this take the implicit functions?

def implctest[T](a: T)(implicit b:T=>T):T = {b apply a}
class Testimplcl(val a:Int){
    override def toString() = "value of the 'a' is = "+a
}
implicit def dble(x: Int):Int = {x + x}
implicit def stringer(x: String):String = {x+" no not a pity"}
implicit def myclass(x: Testimplcl):Testimplcl = new Testimplcl(x.a +1)

implctest[String]("oh what a pity")
implctest[Int](5)
implctest[Testimplcl](new Testimplcl(4))

None of my implicit defs in local scope are taken in. For eg the implctestInt gives result 5, I expect it to return 10 by taking the dble as implicit.

It does not show error also. implctest simply returns the arguments passed in.

Was it helpful?

Solution

When you ask for a function A => A, Scala provides an implicit lift from a method definition, such as

implicit def dble(x: Int):Int = x + x

That is, it will treat that as a function dble _. So in the implicit resolution, this is not an immediately available value.

The problem you have is that there is an implicit A => A for any type, defined as Predef.conforms:

 def conforms[A]: <:<[A, A]   // where <:< is a sub class of A => A

This is useful and necessary because whenever you want a view from A => B and A happens to be B, such a "conversion" is automatically available.

See, with a direct function:

implicit val dble = (x: Int) => x + x

You see the conflict:

implicitly[Int => Int]   // look for an implicit conversion of that type

<console>:49: error: ambiguous implicit values:
 both method conforms in object Predef of type [A]=> <:<[A,A]
 and value dble of type => Int => Int
 match expected type Int => Int
              implicitly[Int => Int]
                        ^

So, in short, it's not good to ask for a custom A => A. If you really need such thing, use a custom type class such as Foo[A] extends (A => A).

OTHER TIPS

If you will rewrite your implicits like ths:

implicit val dble = (x: Int) => x + x
implicit val stringer = (x: String) => x + " no not a pity"
implicit val myclass = (x: Testimplcl) => new Testimplcl(x.a +1)

then you will immediately see the reason for this behavior. Now you have the problem with ambiguous implicit values:

scala: ambiguous implicit values:
  both method conforms in object Predef of type [A]=> <:<[A,A]
and value stringer in object ReflectionTest of type => String => String
match expected type String => String
println(implctest[String]("oh what a pity"))
                  ^

This generally tells you that Predef already defined an implicit function T => T, so it conflicts with your definitions.

I will recommend you not to use such general types as Function as implicit parameters. Just create your own type for this. Like in this example:

trait MyTransformer[T] extends (T => T)

object MyTransformer {
  def apply[T](fn: T => T) = new MyTransformer[T] {
    def apply(v: T) = fn(v)
  }
}

def implctest[T: MyTransformer](a: T): T =
  implicitly[MyTransformer[T]] apply a


class Testimplcl(val a:Int){
  override def toString() = "value of the 'a' is = "+a
}

implicit val dble = MyTransformer((x: Int) => x + x)
implicit val stringer = MyTransformer((x: String) => x + " no not a pity")
implicit val myclass = MyTransformer((x: Testimplcl) => new Testimplcl(x.a +1))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top