6 votes

Priorité Implicit ExecutionContext dans Scala 2.12

Dans Scala 2.12, l'importation du global et qu'un autre contexte d'exécution implicite est défini dans la portée, cela donne un implicite ambigu, alors que dans la version 2.11, cela fonctionne parfaitement.

import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global

class A(implicit ec: ExecutionContext) {
  x = implicitly[ExecutionContext]
}

Le compilateur donne une erreur :

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]
                         ^

Quelle est la cause de ce problème et comment le contourner en code ?

2voto

som-snytt Points 17224

La spécification traite la résolution de surcharge comme la désambiguïsation d'une sélection de membres d'une classe. Mais la résolution implicite utilise la résolution statique des surcharges pour choisir entre des références qui ne sont pas des membres.

On peut soutenir que ce qui suit est une mauvaise interprétation de la spécification, puisque zzz est défini dans une classe dérivée de X autant que yyy est :

$ 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] }
                                                                             ^

Actuellement, vous devez compter sur le nommage pour masquer l'implicite de la portée englobante :

scala> class Z extends X { def f(implicit xxx: ExecutionContext) = implicitly[ExecutionContext] }
defined class Z

Ou,

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>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X