2015-01-14 14 views
7

In meinem Scala-Code, ich habe einige implizite Konvertierung, und ich habe die notwendige Import vorhanden:Warum warnen, wenn scala.language.implicitConversions nicht der letzte Import ist?

import scala.language.implicitConversions 

Aber manchmal, wenn ein anderer es Import nach diesem getan, erhalte ich die Warnung als ob der Import dort überhaupt nicht:

Warnung: (112, 18) implizites Umwandlungsverfahren pair2Dimension indem der implizite Wert scala.language.implicitConversions sichtbar aktiviert werden soll.

build.sbt:

name := "ImplicitSBT" 

version := "1.0" 

scalaVersion := "2.11.5" 

scalacOptions ++= Seq("-deprecation","-feature") 

libraryDependencies += "org.scala-lang.modules" %% "scala-swing" % "1.0.1" 

Main.scala:

import scala.language.implicitConversions 
import scala.swing.{Action, _} 

object Main extends App { 

    implicit def pair2Dimension(pair: (Int, Int)): Dimension = new Dimension(pair._1, pair._2) 

    val dim : Dimension = (0,0) 

    println(dim) 


} 

Warum passiert das das? Wie versteckt sich import scala.swing.{Action, _} der implicitConversions Import?

Antwort

4

Wie ist import scala.swing. {Aktion, _} versteckt den ImplicitConversions Import?

Ihr:

import scala.language.implicitConversions 

... wird von implicitConversionsdefined in scala.swing Paketobjekt beschattet:

package scala 

... 

package object swing { 

... 

implicit lazy val implicitConversions = scala.language.implicitConversions 

... 

} 

Da Sie hier Wildcard Import verwenden:

import scala.swing.{Action, _} 

... scala.swing.implicitConversions wird von scala.swing importiert und am Ende Schatten scala.language.implicitConversions. Die interessante Frage lautet: Warum scalac nicht herausfinden kann, dass die Sprachfunktion aktiviert ist, wenn es zwei "Feature Flags" (implicitConversions in diesem Fall) gibt, die eine andere auf derselben Ebene schattieren.

Dies könnte ein Fehler sein sowie Besonderheiten wie SIP 18 implementiert ist.

Wie dem auch sei, dieses Problem zu lösen ich Sie einen der folgenden Schritte zu tun vorschlagen kann:

  1. importiere nicht scala.language.implicitConversions (wie es bereits importiert wird, wenn Wildcard Import scala.swing)

  2. nicht tun Platzhalterimport von scala.swing (verschmutzen Sie nicht Ihren Umfang und importieren Sie stattdessen, was Sie benötigen)

  3. einen weiteren Import (der nicht von einem anderen beschattet wird) von implicitConversions an Ihrer Main Objektebene

+0

Um es klar zu machen: Die interessante Frage ist nicht, warum die beiden kollidieren (das ist zu erwarten), aber warum nicht, wenn der Import von "scala.language" an zweiter Stelle steht. –

+0

@Travis Ich denke, dass ein bestimmter (Ein-Name) Import Vorrang vor einem Wildcard-Import hat, der davor ausgeführt wurde. – Suma

+0

@Suma oh, richtig, das macht Sinn. Das ist also nicht zu geheimnisvoll. –

1

Dies ist ein Fehler in der impliziten Lookup.

Hier ist die gleiche Struktur in mehr normalen Code, wo die erforderlichen implizit ist der Ausführungskontext.

(Es spielt keine Rolle, ob der Wildcard-Import aus einem Paket-Objekt ist, oder ob das andere Paket ist in derselben Übersetzungseinheit.)

Da der Code mit einer expliziten global kompiliert, soll es kompilieren mit ein implizites arg.

Ein Implizit ist verfügbar, wenn es sein kann.

Die binding precedence ist von der Reihenfolge der Quellcodes nicht betroffen. Das Schattieren funktioniert auf die übliche Weise; Eine Bindung überschattet niemals eine Bindung höherer Priorität.

/* 
package object bound2 { 
    implicit lazy val global = scala.concurrent.ExecutionContext.Implicits.global 
} 
*/ 
package bound2 { 
    object B { 
    implicit lazy val global: concurrent.ExecutionContextExecutor = scala.concurrent.ExecutionContext.global 
    } 
} 

package bound { 
    // the order of these imports in the same scope should not matter 
    import scala.concurrent.ExecutionContext.Implicits.global 
    import bound2.B._ 

    object Test extends App { 
    val f = concurrent.Future(42) //(global) // explicit arg works 
    Console println concurrent.Await.result(f, concurrent.duration.Duration.Inf) 
    } 
} 

Im spec Beispiel 2.0.1, das Hinzufügen der Zeile „OK“ kompiliert markiert, und Sie können diese Reihenfolge überprüfen spielt keine Rolle, aber es wird nicht eindeutig in dem inneren Umfang, weil die „Wildcard y“ gibt nicht die "explizite y" Schatten von dem äußeren Umfang:

import X.y   // `y' bound by explicit import 
    println("L16: "+y) // `y' refers to `Q.X.y' here 
    import P.X._ 
    println("OK: "+y) // `y' refers to `Q.X.y' here 

    locally { val x = "abc"  // `x' bound by local definition 
     import P.X._  // `x' and `y' bound by wildcard import 
//  println("L19: "+y) // reference to `y' is ambiguous here 
+0

Zuvor, https://issues.scala-lang.org/browse/SI-4270 –

+0

https://issues.scala-lang.org/browse/SI-9208 –

3

wie in

http://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html

ein Wildcard-Import (wie Sie geschrieben haben) gibt zu jedem Swin g implizite Definitionen haben eine ziemlich hohe Priorität und das verdeckt eindeutig Ihre.

Da Sie mit SBT sind kompilieren, wäre es nicht viel einfacher, das folgende passieren Einstellung

scalacOptions ++= Seq(
    "-feature", 
    "-language:implicitConversions" 
) 

und aufhören sich Gedanken darüber, was ist der richtige Ort, um scala.language.implicitConversions zu importieren?

+0

Irgendwie finde ich Import-Reiniger als eine Compiler-Option. Mag nur ich sein. – Suma

Verwandte Themen