-
Notifications
You must be signed in to change notification settings - Fork 21
Predef.conforms chosen in preference to a locally defined implicit function for type (Int => Int) [2.8.0 regression] #2811
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Imported From: https://issues.scala-lang.org/browse/SI-2811?orig=1 |
@odersky said: scala> implicit def conforms = (s: String) => "s2s"
conforms: (String) => java.lang.String
scala> def implicitly[A](implicit a: A) = a
implicitly: [A](implicit a: A)A
scala> implicitly[String => String].apply("foo")
res0: String = s2s The thing to keep in mind is that both the local and the Predef implicit are regarded as competing, unless they have the same name (in which case the local implicit will shadow the Predef implicit). In the example as given, the local implicit was a val and the Predef implicit was a def and the rules of overloading resolution pick the val over the def. |
@odersky said: |
@retronym said: The change in Predef to return a (A <:< A) from conforms solves other problems, but there is no way to be backwards compatible without a special case in the compiler. I played around with this some more and found a few more unexplained phenomona -- see the inline comments below. object test1 {
implicit def s2s(s: String): String = "s2s"
assert(implicitly[String => String].apply("foo") == "foo")
// Predef.conforms chosen here because it returns the required type (A => A),
// so no need to try to eta transform the method s2s. Fair enough.
}
object test2 {
locally {
// s2s is a def inside a block. it seems to be automatically eta transformed to (String => String),
// and is considered equally with conforms[A].
implicit def s2s(s: String): String = "s2s"
// assert(implicitly[String => String].apply("foo") == "foo")
// UNCOMMENT LINE ABOVE FOR:
// error: ambiguous implicit values:
// both method s2s of type (s: String)java.lang.String
// and method conforms in object Predef of type [A]<:<[A,A]
// match expected type (String) => String
}
}
object test3 {
def s2s(s: String) = "s2s"
locally {
// here we ensure that (String => String) is implicit rather than a method. But why is this chosen now, rather than
// getting the ambiguity error as in `test2`?
implicit val _ = s2s _
assert(implicitly[String => String].apply("foo") == "s2s")
}
locally {
implicit def conforms(s: String) = "s2s" // shadowing Predef.conforms by name works. But pretty it ain't.
assert(implicitly[String => String].apply("foo") == "s2s")
}
} |
@retronym said: sealed abstract class <:<[-From, +To] extends (From => To)
object <:< {
implicit def conforms[A]: A <:< A = new (A <:< A) {
def apply(x: A) = x
}
}
object Predef {
implicit def identity[A](a: A) = a
}
According the the comments, the new design should have less scope for ambiguity. I need an example to understand this and weigh against this problem. r18537 |
@adriaanm said: In hindsight, this design ignored at least one limitation of our implicit resolution scheme (see #2781) Overall, I would not recommend using implicit values of function type, as that interacts strangely with implicit conversions (unless of course you want an implicit conversion and not the encoding of some witness to a typing constraint). |
As discovered by Alexander: http://old.nabble.com/Puzzle-td26827682.html
The text was updated successfully, but these errors were encountered: