In my Scala code, I have some implicit conversion, and I have the necessary import present:
import scala.language.implicitConversions
However, sometimes when there is another import done after this one, I get the warning as if the import is not there at all:
Warning:(112, 18) implicit conversion method pair2Dimension should be enabled by making the implicit value scala.language.implicitConversions visible.
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)
}
Why does this happen? How is import scala.swing.{Action, _}
hiding the implicitConversions
import?
As explained in
http://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html
a wildcard import (as you wrote) gives to any Swing implicit definitions a quite high priority and that's clearly hiding yours.
Since you're compiling with SBT, wouldn't it be much easier to pass the following setting
scalacOptions ++= Seq(
"-feature",
"-language:implicitConversions"
)
and stop worrying about what's the right place to import scala.language.implicitConversions
?
How is import scala.swing.{Action, _} hiding the implicitConversions import?
Your:
import scala.language.implicitConversions
... gets shadowed by implicitConversions
defined in scala.swing
package object:
package scala
...
package object swing {
...
implicit lazy val implicitConversions = scala.language.implicitConversions
...
}
Since you are using wildcard import here:
import scala.swing.{Action, _}
... scala.swing.implicitConversions
gets imported from scala.swing
and in the end shadows scala.language.implicitConversions
.
The interesting question is: why scalac
fails to figure out that language feature is enabled if there are two "feature flags" (implicitConversions
in this case), one shadowing another at the same level.
This might be a bug as well as specifics of how SIP 18 is implemented.
Anyway, to solve this I can suggest you to do one of the following:
do not import scala.language.implicitConversions
(as it is already imported when wildcard importing scala.swing
)
do not do wildcard import from scala.swing
(do not pollute your scope and import what you need instead)
do another import (that is not shadowed by another) of implicitConversions
at your Main
object level
This is a bug in the implicit lookup.
Here is the same structure in more normal code, where the required implicit is the execution context.
(It doesn't matter whether the wildcard import is from a package object, or whether the other package is in the same compilation unit.)
Since the code compiles with an explicit global
, it should compile with an implicit arg.
An implicit is available if it can be accessed without a prefix.
The binding precedence is not affected by source code order. Shadowing works in the usual way; a binding never shadows a binding of higher precedence.
/*
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)
}
}
In the spec example 2.0.1, adding the line marked "OK" compiles, and you can verify that order doesn't matter, but it becomes ambiguous in the inner scope because the "wildcard y" there does not shadow the "explicit y" from the outer scope:
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
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