Domanda

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.

È stato utile?

Soluzione

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).

Altri suggerimenti

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))
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top