2016-11-05 4 views
6

In Scala 2.12 importiert den global Ausführungskontext und dann einen anderen impliziten Ausführungskontext im Bereich definiert führt zu einem mehrdeutigen implizit, während in 2.11 es funktioniert gut.Implizite ExecutionContext-Priorität in Scala 2.12

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

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

Compiler gibt Fehler:

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

Was ist die Ursache dafür, und wie um es im Code zu arbeiten?

+1

Das entsprechende Commit im Scala/Scala Repo ist https://github.com/scala/scala/commit/44953dcb08fc5dd92e423a56bd42bcc32757aaef und die Begründung für die Änderung ist https://issues.scala-lang.org/browse/SI-8849 –

+0

Viktor Klang kommentiert das JIRA-Ticket: "empfehlen, ExecutionContext.global entweder explizit zu übergeben oder ihr eigenes implizites val einzufügen, wenn nötig" –

+0

Wenn ich das Problem richtig verstanden habe, funktioniert es in 2.11 tatsächlich "falsch" oder sehr am wenigsten unerwartet, da das "global" über das implizite im scope ausgewählt wird? Und 2.12 entlarvt diesen möglichen Programmierfehler, indem er ihn mehrdeutig macht. Erwähnenswert wäre dies in den Release Notes und/oder in der Dokumentation. – ochrons

Antwort

2

Die Spezifikation behandelt die Überladungsauflösung als Disambiguierung einer Auswahl von Mitgliedern einer Klasse. Aber die implizite Auflösung verwendet die statische Überladungsauflösung, um zwischen Referenzen zu wählen, die keine Mitglieder sind.

Argumentieren, die folgende ist eine Fehlinterpretation der Spezifikation, da zzz in einer Klasse von X viel wie yyy abgeleitet definiert ist:

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

Derzeit müssen Sie auf die Benennung verlassen, um die impliziten von umschließenden beschatten Umfang:

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

Oder

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>