In Scala 2.12 importing the global
execution context and then having another implicit execution context defined in the scope results in an ambiguous implicit, while in 2.11 it works just fine.
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
class A(implicit ec: ExecutionContext) {
x = implicitly[ExecutionContext]
}
Compiler gives error:
error: ambiguous implicit values:
both lazy value global in object Implicits of type => scala.concurrent.ExecutionContext
and value ec in class A of type scala.concurrent.ExecutionContext
match expected type scala.concurrent.ExecutionContext
val x = implicitly[ExecutionContext]
^
What is the cause of this and how to work around it in code?
The spec treats overload resolution as the disambiguation of a selection of members of a class. But implicit resolution uses static overload resolution to choose between references which are not members.
Arguably, the following is a misinterpretation of the spec, since zzz
is defined in a class derived from X
much as yyy
is:
$ scala
Welcome to Scala 2.12.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_101).
Type in expressions for evaluation. Or try :help.
scala> import concurrent._, ExecutionContext.global
import concurrent._
import ExecutionContext.global
scala> trait X { implicit val xxx: ExecutionContext = global }
defined trait X
scala> class Y extends X { implicit val yyy: ExecutionContext = global ; def f = implicitly[ExecutionContext] }
defined class Y
scala> class Z extends X { def f(implicit zzz: ExecutionContext) = implicitly[ExecutionContext] }
<console>:16: error: ambiguous implicit values:
both value xxx in trait X of type => scala.concurrent.ExecutionContext
and value zzz of type scala.concurrent.ExecutionContext
match expected type scala.concurrent.ExecutionContext
class Z extends X { def f(implicit zzz: ExecutionContext) = implicitly[ExecutionContext] }
^
Currently, you must rely on naming to shadow the implicit from enclosing scope:
scala> class Z extends X { def f(implicit xxx: ExecutionContext) = implicitly[ExecutionContext] }
defined class Z
Or,
scala> :pa
// Entering paste mode (ctrl-D to finish)
package object p { import concurrent._ ; implicit val xxx: ExecutionContext = ExecutionContext.global }
package p { import concurrent._ ;
class P { def f(implicit xxx: ExecutionContext) = implicitly[ExecutionContext]
def g = implicitly[ExecutionContext] }
}
// Exiting paste mode, now interpreting.
scala>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With