View bounds and ambiguous implicit conversion error - scala

This is a much simpler version of my earlier post ambiguous implicit conversion errors
Here is a code snippet from the post How can I chain implicits in Scala?
class A(val n: Int)
class B(val m: Int, val n: Int)
class C(val m: Int, val n: Int, val o: Int) {
def total = m + n + o
}
object T2 {
implicit def toA(n: Int): A = new A(n)
implicit def aToB[A1 <% A](a: A1): B = new B(a.n, a.n)
implicit def bToC[B1 <% B](b: B1): C = new C(b.m, b.n, b.m + b.n)
// works
println(5.total)
println(new A(5).total)
println(new B(5, 5).total)
println(new C(5, 5, 10).total)
}
Now if I add a class D and implicit def dToC as follows, I get errors at locations shown in the snippet.
class A(val n: Int)
class B(val m: Int, val n: Int)
class D(val m: Int, val n: Int) //Added by me
class C(val m: Int, val n: Int, val o: Int) {
def total = m + n + o
}
object T2 {
implicit def toA(n: Int): A = new A(n)
implicit def aToB[A1 <% A](a: A1): B = new B(a.n, a.n)
implicit def bToC[B1 <% B](b: B1): C = new C(b.m, b.n, b.m + b.n)
implicit def dToC[D1 <% D](d: D1): C = new C(d.m, d.n, d.m + d.n) //Added by me
println(5.total) //Ambiguous implicit conversion error
println(new A(5).total) //Ambiguous implicit conversion error
println(new B(5, 5).total) //Ambiguous implicit conversion error
println(new C(5, 5, 10).total)
}
I don't understand how both bToC and dToC are possible conversion functions for say println(new B(5, 5).total).

View bounds obviously get translated to an extra implicit function parameter. So both bToC and dToC get translated to [T](x: T)(implicit f: T => Something): C
The issue being that the compiler disregards the presence/absence of implicit arguments in the ambiguity check.
case class Foo[A](value: A)
implicit def foo[A](x: A)(implicit ev: Any =:= String) = Foo(x)
implicit def bar[A](x: A)(implicit ev: Any =:= Int) = Foo(x)
1.value //Ambiguous though none are applicable

(1) Int=>A=>B=>C
(2) Int=>A=>D=>C
2 paths can be chosen, and the compiler don't know which path to go, so that's why ambiguous implicit conversion error was raised.

Related

Implement the realization of function in scala

I have a function
def foo[A](a1: A, a2: A): A = a1|+|a2
It need to implement the realization
The result must be:
foo[Test](Test(1), Test(2)) // Test(3)
I wrote some code in IDEA worksheet, but it is not compile
case class Test(num: Int)
object Test {
implicit val test = new Writer[Test] {
def write(v1: Test, v2: Test) = {
Test(v1.num + v2.num)
}
}
}
trait Writer[A] {
def write(v1: A, v2: A): A
}
implicit class someT[A](a1: A) {
def |+|(a2: A)(implicit writer: Writer[A]) = {
writer.write(a1, a2)
}
}
def foo[A](a1: A, a2: A): A = a1|+|a2
foo[Test](Test(1), Test(2))
the output error is:
Error:(32, 34) could not find implicit value for parameter writer: A$A213.this.Writer[A]
def foo[A](a1: A, a2: A): A = a1|+|a2
^
Error:(32, 34) not enough arguments for method |+|: (implicit writer: A$A213.this.Writer[A])A.
Unspecified value parameter writer.
def foo[A](a1: A, a2: A): A = a1|+|a2
^
You're missing the implicit Writer[A] required on foo:
def foo[A](a1: A, a2: A)(implicit writer: Writer[A])
Or if you prefer context bounds:
def foo[A : Writer](a1: A, a2: A)
Now, the compiler can in turn see that |+| has a Writer[A] in scope.

Scala: implicitly convert Option to Option of implicit class [duplicate]

I'm trying to write a function which re-uses the implicit conversions which I have for Object A -> Object B when they are wrapped in an Option in a generic way so that Option[A] -> Option[B] conversions also work.
What I've come up with is:
implicit def fromOptionToOption[A, B](from: Option[A])(implicit conversion: (A) => B): Option[B] = from.map(conversion(_))
This works when I assign a Some(..) to a value but not when I assign an Option val; see the following console output:
scala> trait T
defined trait T
scala> case class Foo(i: Int) extends T
defined class Foo
scala> case class Bar(i: Int) extends T
defined class Bar
scala> implicit def fromFooToBar(f: Foo):Bar = Bar(f.i)
fromFooToBar: (f: Foo)Bar
scala> implicit def fromBarToFoo(b: Bar):Foo = Foo(b.i)
fromBarToFoo: (b: Bar)Foo
scala> implicit def fromOptionToOption[A, B](from: Option[A])(implicit conversion: (A) => B): Option[B] = from.map(conversion(_))
fromOptionToOption: [A, B](from: Option[A])(implicit conversion: (A) => B)Option[B]
scala> val foo: Option[Foo] = Some(Bar(1))
foo: Option[Foo] = Some(Foo(1))
// THIS WORKS as expected
scala> val fooOpt = Some(Foo(4))
fooOpt: Some[Foo] = Some(Foo(4))
scala> val barOpt2: Option[Bar] = fooOpt
<console>:16: error: type mismatch;
found : Some[Foo]
required: Option[Bar]
val barOpt2: Option[Bar] = fooOpt
^
//THIS FAILS.
I don't really see the difference between the first and second conversion. Somehow it doesn't invoke the implicit conversion in the latter. I guess it has something to do with the type system, but I can't see how just yet. Any ideas?
-Albert
(I'm on scala 2.9.1)
Here's clue:
scala> val fooOpt: Option[Bar] = Option(Foo(1))
fooOpt: Option[Bar] = Some(Bar(1))
And another:
scala> implicit def foobar(x: String): Int = augmentString(x).toInt
foobar: (x: String)Int
scala> val y: Option[String] = Option(1)
y: Option[String] = Some(1)
scala> val y: Option[Int] = Option("1")
y: Option[Int] = Some(1)
Looks like a legitimately odd bug. I'd pop open a smaller test case and open an issue (or search for one in JIRA).
As an aside:
You could use some category theory to handle lots of different types of "Option-ish" things.
package object fun {
trait Functor[Container[_]] {
def fmap[A,B](x: Container[A], f: A => B): Container[B]
}
object Functor {
implicit object optionFunctor extends Functor[Option] {
override def fmap[A,B](x: Option[A], f: A => B): Option[B] = x map f
}
// Note: With some CanBuildFrom magic, we can support Traversables here.
}
implicit def liftConversion[F[_], A, B](x: F[A])(implicit f: A => B, functor: Functor[F]): F[B] =
functor.fmap(x,f)
}
That's a bit more advanced, as you're mapping some category theory FP onto the problem, but it's a more general solution to lift implicit conversations into containers as needed. Notice how they chain by using one implicit conversation method that takes a more limited implicit argument.
ALSO, this should make the examples work:
scala> val tmp = Option(Foo(1))
tmp: Option[Foo] = Some(Foo(1))
scala> val y: Option[Bar] = tmp
y: Option[Bar] = Some(Bar(1))
And make your usage of Some more dangerous:
scala> val tmp = Some(Foo(1))
tmp: Some[Foo] = Some(Foo(1))
scala> val y: Option[Bar] = tmp
<console>:25: error: could not find implicit value for parameter functor: fun.Functor[Some]
val y: Option[Bar] = tmp
^
That's telling you that variance is critical, and interacts with implicits. My guess is you ran into a very rare, probably hard to fix bug that can be avoided using other techniques.
You might not be aware of it, but there's a flag for that: -Xlog-implicits. And this is what it says:
scala> val barOpt2: Option[Bar] = fooOpt
fromOptionToOption is not a valid implicit value for Some[Foo] => Option[Bar] because:
incompatible: (from: Option[Foo])(implicit conversion: Foo => B)Option[B] does not match expected type Some[Foo] => Option[Bar]
<console>:16: error: type mismatch;
found : Some[Foo]
required: Option[Bar]
val barOpt2: Option[Bar] = fooOpt
^
And there you go -- it doesn't know what type B must be. 0__ mentioned that this problem doesn't happen with invariant collections, and that makes some sense. In invariant collections, B must be exactly Bar, while for covariant collections it could be any subtype of Bar.
So, why does val foo: Option[Foo] = Some(Bar(1)) work? Well, there's a flag for that too... -Ytyper-debug. Not for the weak, however, given the extreme verbosity.
I waddled through anyway, comparing what happens in both cases, and the answer is rather simple... it's not the Option that is being converted in that case, but Bar! Remember, you declared an implicit conversion from Bar => Foo, so it is applying that conversion before passing the result to Some!
It doesn't work because the Scala Language Specification defines view as follows:
Implicit parameters and methods can also define implicit conversions called views. A view from type S to type T is defined by an implicit value which has function type S=>T or (=>S)=>T or by a method convertible to a value of that type.
fromOptionToOption doesn't conform to the three categories since it takes an implicit parameter. Compiler doesn't seem to find converter with both destination and source having generic type.
Defining a view from Option[Foo] to Option[Bar] works as expected.
trait T
case class Foo(i: Int) extends T
case class Bar(i: Int) extends T
object Main {
implicit def fromFooToBar(f: Foo):Bar = Bar(f.i)
implicit def fromBarToFoo(b: Bar):Foo = Foo(b.i)
// implicit def fromOptionToOption[A, B](from: Option[A])(implicit conversion: (A) => B): Option[B] =
// from.map(conversion(_))
implicit def fromOptionFooToOptionBar(o: Option[Foo]): Option[Bar] = o map { foo => foo }
def test(): Option[Bar] = {
val fooOpt = Some(Foo(4))
val barOpt2: Option[Bar] = fooOpt
barOpt2
}
}
println(Main.test)
Running this prints out:
$ scala so.scala
Some(Bar(4))
However, all is not lost. It's not as nice as general Option to Option, but we can do something like anything that can turn into Bar to Option[Bar] by view bound.
trait T
case class Foo(i: Int) extends T
case class Bar(i: Int) extends T
object Main {
implicit def fromFooToBar(f: Foo):Bar = Bar(f.i)
implicit def fromBarToFoo(b: Bar):Foo = Foo(b.i)
implicit def fromOptionToOptionBar[A <% Bar](from: Option[A]): Option[Bar] =
from map { foo => foo }
def test(): Option[Bar] = {
val fooOpt = Some(Foo(4))
val barOpt2: Option[Bar] = fooOpt
barOpt2
}
}
println(Main.test)
Here's another workaround that can be used for general Option to Option but requires extra .convert call:
trait T
case class Foo(i: Int) extends T
case class Bar(i: Int) extends T
case class Converter[A](x: Option[A]) {
def convert[B](implicit ev: Function1[A, B]): Option[B] = x map { a: A => ev(a) }
}
object Main {
implicit def optionToConverter[A](x: Option[A]) = Converter(x)
implicit def fooToBar(x: Foo) = Bar(x.i)
def test(): Option[Bar] = {
val fooOpt = Some(Foo(4))
val barOpt: Option[Bar] = fooOpt.convert
barOpt
}
}
println(Main.test)
Indeed it's a very strange problem. I tried to use another type than Option, and it turns out that the problem is that Option is covariant in its type parameter. This works all:
case class A[B](value: B) // invariant in B
case class X()
case class Y()
implicit def xtoy(x: X): Y = Y()
implicit def ytox(x: Y): X = X()
implicit def movea[U, V](from: A[U])(implicit view: U => V): A[V] = A[V](from.value)
def test(a: A[Y]) = "ok"
test(A(X())) // (1)
val f = A(X())
test(f) // (2)
But if instead I define A as
case class A[+B](value: B) // covariant in B
The case (2) fails. Case (1) always succeeds, because Scala already converts X to Y before wrapping it in an A.
Now that we know the problem source, you need to wait for a type guru to explain why this is actually a problem... The conversion is still valid, you see:
askForY(movea(f)) // succeeds, even with A[+B]
I improved #jseureth answer and added support for Traversable:
trait Mappable[A, B, C[_]] {
def apply(f: A => B): C[B]
}
package object app {
implicit class OptionMappable[A, B, C[X] <: Option[X]](option: C[A]) extends Mappable[A, B, Option] {
override def apply(f: A => B): Option[B] = option.map(f)
}
implicit class TraversableMappable[A, B, C[X] <: Traversable[X]](traversable: C[A])
(implicit cbf: CanBuildFrom[C[A], B, C[B]]) extends Mappable[A, B, C] {
override def apply(f: A => B): C[B] = {
val builder = cbf(traversable)
builder.sizeHint(traversable)
builder ++= traversable.map(f)
builder.result()
}
}
implicit def liftConversion[C[_], A, B](x: C[A])
(implicit f: A => B, m: C[A] => Mappable[A, B, C]): C[B] = m(x)(f)
}
Now you can implicitly convert options and traversables:
implicit def f(i: Int): String = s"$i"
val a: Option[String] = Some(1)
val b: Seq[String] = Seq(1, 2, 3)

Chain implicit conversion of collection

I fail make an implicit conversion List[A] => List[B], given implicit conversion A => B.
There is a very related question that has a solution but does not work for me. Also, here is a nice documentation for chaining implicits, which I used as the base of my code below.
The point I try to make in the code below is that chaining implicits works fine in all expected cases, even for collection-like objects like the Container below, but fails for collections:
object ChainImplicits extends App{
case class A(n: Int)
implicit def toA(n: Int): A = A(n)
case class B(m: Int, n: Int)
implicit def aToB[T](a: T)(implicit f: T => A): B = B(a.n, a.n)
case class C(m: Int, n: Int, o: Int) {
def total = m + n + o
}
implicit def bToC[T](b: T)(implicit f: T => B): C = C(b.m, b.n, b.m + b.n)
// works
println(5.total)
println(new A(5).total)
println(new B(5, 5).total)
println(new C(5, 5, 10).total)
case class Container[T](value:T) {
def map[B](f: T => B) = Container(f(value))
}
implicit def ContainerConv[A,B](container:Container[A])
(implicit f: A => B): Container[B] = container.map(f)
val container = Container(1)
container.value.total //Works, as expected
def containerCTotal(containerC: Container[C]) = containerC.value.total
containerCTotal(container) //Works too!
implicit def listConv[A,B](collection: List[A])
(implicit f: A => B): List[B] = collection.map(f)
val list = List(1)
def CTotals(list: List[C]) = list.map(_.total)
CTotals(listConv(list)) //Explicit conversion works, finds the chain implicit conversions Int => C :)
CTotals(list) //... but implicit does not :(
def ATotals(list: List[A]) = list.map(_.total)
ATotals(list) // Simple (non-chained) conversion of contained values does not work either :(
}
How can I make these last conversions work?
I also tried the (deprecated) view bounds, getting the same results:
implicit def convert[B, A <% B](l: List[A]): List[B] = l map { a => a: B }
Just in case, the compilation error is the expected:
type mismatch;
found : List[Int]
required: List[ChainImplicits.C]
CTotals(list) //... but implicit does not :(
And similarly for ATotals(list)
I tried it on scala versions 2.11.8 and 2.11.4.
UPDATE:
I confirmed after Andreas' comment that the underlying issue has something to do with the List being covariant. Giving covariance to the Container class above (i.e. Container[+A]) makes the previously working implicit conversion at containerCTotal(container) to fail.

Safely chaining implicit conversions

You can do this to get implicit conversions to chain:
package language
object chainedImplicits {
implicit def chainImplicits[A, B, C](a: A)(implicit conv1: A => B, conv2: B => C): C = conv2(conv1(a))
}
but this is obviously not safe.
I can't see anything wrong with this version, though:
package language
package chainedImplicits {
final class Chained[A, B] private[chainedImplicits] (val f: A => B)
trait Low { this: `package`.type =>
implicit def startChaining(implicit conv: A => B): Chained[A, B] = new Chained[A, B](conv)
implicit def chainImplicits[A, B, C](implicit conv1: Chained[A, B], conv2: B => C): Chained[B, C] = new Chained(conv1.f andThen conv2)
}
}
package object chainedImplicits extends Low {
implicit def endChain[A, B](a: A)(implicit conv: Chained[A, B]): B = conv.f(a)
}
Is there a catch here?
First, I can't get your first "obviously not safe" example to do anything:
import language.implicitConversions
object Test {
implicit def chain[A, B, C](a: A)(implicit ab: A => B, bc: B => C): C = bc(ab(a))
case class X()
case class Y()
case class Z()
implicit def xy(x: X) = Y()
implicit def yz(y: Y) = Z()
val z: Z = X()
}
...
type mismatch;
found : Test.X
required: Test.Z
val z: Z = X()
^
Next, the obvious "catch" in your second example is that it doesn't compile. Did you actually try it? Regardless, after "fixing" it, it still doesn't do what you want:
import language.implicitConversions
class Convert[A, B](val convert: A => B) extends AnyVal
trait Convert0 {
implicit def convert[A, B](implicit ab: A => B): Convert[A, B] = new Convert(ab)
implicit def convert[A, B, C](implicit ab: Convert[A, B], bc: B => C): Convert[A, C] = new Convert(ab.convert andThen bc)
}
object Convert extends Convert0 {
implicit def convert[A, B](a: A)(implicit convert: Convert[A, B]): B = convert.convert(a)
}
object Test {
case class X()
case class Y()
case class Z()
implicit def xy(x: X) = Y()
implicit def yz(y: Y) = Z()
val z: Z = X()
}
This gives the same type mismatch error. To my knowledge, if you want implicit conversions to chain, you have to be explicit about it:
import language.implicitConversions
object test {
case class X()
case class Y()
case class Z()
// anything convertible to X is convertible to Y
implicit def xy[A <% X](x: A) = Y()
// anything convertible to Y is convertible to Z
implicit def yz[B <% Y](y: B) = Z()
val z: Z = X()
}

How can I chain implicits in Scala?

The pimp-my-library pattern allows me to seemingly add a method to a class by making available an implicit conversion from that class to one that implements the method.
Scala does not allow two such implicit conversions taking place, however, so I cannot got from A to C using an implicit A to B and another implicit B to C. Is there a way around this restriction?
Scala has a restriction on automatic conversions to add a method, which is that it won't apply more than one conversion in trying to find methods. For example:
class A(val n: Int)
class B(val m: Int, val n: Int)
class C(val m: Int, val n: Int, val o: Int) {
def total = m + n + o
}
// This demonstrates implicit conversion chaining restrictions
object T1 { // to make it easy to test on REPL
implicit def toA(n: Int): A = new A(n)
implicit def aToB(a: A): B = new B(a.n, a.n)
implicit def bToC(b: B): C = new C(b.m, b.n, b.m + b.n)
// won't work
println(5.total)
println(new A(5).total)
// works
println(new B(5, 5).total)
println(new C(5, 5, 10).total)
}
EDIT: View bounds ('<%') are deprecated since Scala 2.11 https://issues.scala-lang.org/browse/SI-7629 (You can use type classes instead)
However, if an implicit definition requires an implicit parameter itself(View bound), Scala will look for additional implicit values for as long as needed. Continue from the last example:
// def m[A <% B](m: A) is the same thing as
// def m[A](m: A)(implicit ev: A => B)
object T2 {
implicit def toA(n: Int): A = new A(n)
implicit def aToB[A1 <% A](a: A1): B = new B(a.n, a.n)
implicit def bToC[B1 <% B](b: B1): C = new C(b.m, b.n, b.m + b.n)
// works
println(5.total)
println(new A(5).total)
println(new B(5, 5).total)
println(new C(5, 5, 10).total)
}
"Magic!", you might say. Not so. Here is how the compiler would translate each one:
object T1Translated {
implicit def toA(n: Int): A = new A(n)
implicit def aToB(a: A): B = new B(a.n, a.n)
implicit def bToC(b: B): C = new C(b.m, b.n, b.m + b.n)
// Scala won't do this
println(bToC(aToB(toA(5))).total)
println(bToC(aToB(new A(5))).total)
// Just this
println(bToC(new B(5, 5)).total)
// No implicits required
println(new C(5, 5, 10).total)
}
object T2Translated {
implicit def toA(n: Int): A = new A(n)
implicit def aToB[A1 <% A](a: A1): B = new B(a.n, a.n)
implicit def bToC[B1 <% B](b: B1): C = new C(b.m, b.n, b.m + b.n)
// Scala does this
println(bToC(5)(x => aToB(x)(y => toA(y))).total)
println(bToC(new A(5))(x => aToB(x)(identity)).total)
println(bToC(new B(5, 5))(identity).total)
// no implicits required
println(new C(5, 5, 10).total)
}
So, while bToC is being used as an implicit conversion, aToB and toA are being passed as implicit parameters, instead of being chained as implicit conversions.
EDIT
Related question of interest:
A discussion on types, origin and precedence of implicits
Note that you can build circles with implicit parameters, too. Those are, however, detected by the compiler, as exhibited by this:
class Wrap {
class A(implicit b : B)
class B(implicit c : C)
class C(implicit a : A)
implicit def c = new C
implicit def b = new B
implicit def a = new A
}
The error(s) given to the user are not as clear as they could be, though; it just complains could not find implicit value for parameter for all three construction site. That might obscure the underlying problem in less obvious cases.
Here's a code that also accumulates the path.
import scala.language.implicitConversions
// Vertices
case class A(l: List[Char])
case class B(l: List[Char])
case class C(l: List[Char])
case class D(l: List[Char])
case class E(l: List[Char])
// Edges
implicit def ad[A1 <% A](x: A1) = D(x.l :+ 'A')
implicit def bc[B1 <% B](x: B1) = C(x.l :+ 'B')
implicit def ce[C1 <% C](x: C1) = E(x.l :+ 'C')
implicit def ea[E1 <% E](x: E1) = A(x.l :+ 'E')
def pathFrom(end:D) = end
pathFrom(B(Nil)) // res0: D = D(List(B, C, E, A))