Implicit changes in 2.10

270 views
Skip to first unread message

Johannes Rudolph

unread,
Aug 28, 2012, 6:07:48 AM8/28/12
to scala-l...@googlegroups.com
Hi,

Here are two things we noticed while migrating code to Scala 2.10.0-M7:

In this example [1]:

trait Marker[A]

object TestImplicit {
implicit val TestImplicit: Marker[Int] = null
}

object SameNameNotWorking {
import TestImplicit._

implicitly[Marker[Int]]
}

the implicit isn't found any more with 2.10 if it is named exactly
like its containing class. I would say that's probably as spec'd
because the imported name is shadowed by the (top level) name defined
in the same source file. Workaround: rename the implicit.

Here is another more interesting one [2]:

object InferenceChange {
implicit object StringMarker extends Marker[String]

def getWithMarker[T: Marker]: T = null.asInstanceOf[T]

def func[A: Marker]: Option[A] =
if (true)
None
else
Some(getWithMarker)
}

Here the error message is this:

[error] src/main/scala/InferenceChange.scala:10: ambiguous implicit values:
[error] both object StringMarker in object InferenceChange of type
InferenceChange.StringMarker.type
[error] and value evidence$2 of type Marker[A]
[error] match expected type Marker[T]
[error] Some(getWithMarker)

It seems that the expected type of `func` is not any more regarded for
determining type constraints for the `getWithMarker` call before
looking for implicits. I don't know if it is expected but it means
that in those cases you now need to specify type arguments more often
than before. This may become unwieldy if `getWithMarker` would take
several parameters which could be inferred otherwise. Workaround:
specify the type argument for the getWithMarker call.

I suspect there are several other changes like those, is anyone
collecting for a migration guide?

--
Johannes

[1] https://gist.github.com/3496686#file_src/main/scala/same_name_not_working.scala
[2] https://gist.github.com/3496686#file_src/main/scala/inference_change.scala

-----------------------------------------------
Johannes Rudolph
http://virtual-void.net

Josh Suereth

unread,
Aug 28, 2012, 6:41:54 AM8/28/12
to scala-l...@googlegroups.com

Not yet, but seems a good idea.  Where would you be most likely to write down issues you run into?  Wiki or documentation project or Read me in scala-dist

Daniel Sobral

unread,
Aug 28, 2012, 9:04:17 AM8/28/12
to scala-l...@googlegroups.com
There was one change with regards to implicit that will cause
ambiguities to arise. Eugene Yokota went to the trouble of figuring
out all implicit priority rules, and what in the spec mandated them,
and noticed that there was one not in the spec. It turned out to be a
long standing bug, SI-5354
(https://issues.scala-lang.org/browse/SI-5354), which was fixed. From
the ticket, here's an example of code that previously compiled and now
doesn't (as spec'ed):

package object foo {
implicit val x: Bippy = new Bippy("x")
}
package foo {
class Bippy(override val toString: String){ }
class Dingus {
def f1 = {
implicit val z: Bippy = new Bippy("z")
implicitly[Bippy]
}
}
}

For further information, read the two excellent posts from Eugene
about implicit resolution:
http://eed3si9n.com/revisiting-implicits-without-import-tax and
http://eed3si9n.com/implicit-parameter-precedence-again.

I agree that this kind of information would be useful in a migration
guide. It's past time we started a wiki for that.
--
Daniel C. Sobral

I travel to the future all the time.

Paul Phillips

unread,
Aug 29, 2012, 4:27:09 PM8/29/12
to scala-l...@googlegroups.com
On Tue, Aug 28, 2012 at 3:07 AM, Johannes Rudolph
<johannes...@googlemail.com> wrote:
> I suspect there are several other changes like those, is anyone
> collecting for a migration guide?

Here's something which can incur some head scratching:

import scala.reflect.runtime.{ universe => ru }
import scala.reflect.macros.Context

object R {
import ru._

def f1(c: Context) = {
import c.universe._
(null: Any) match { case Apply(fn, args) => fn }
}
def f2(c: Context) = {
import c.universe.Apply
(null: Any) match { case Apply(fn, args) => fn }
}
}

The pattern matches in f1 and f2 generate different code, because
there is an implicit ClassTag which the pattern matcher uses with the
wildcard import:

def f1(c: scala.reflect.macros.Context): c.universe.Tree = {
import c.universe._;
(null: Any) match {
case c.universe.ApplyTag.unapply(<unapply-selector>) <unapply>
(c.universe.Apply.unapply(<unapply-selector>) <unapply> ((fn @ _),
(args @ _))) => fn
}
};
def f2(c: scala.reflect.macros.Context): c.universe.Tree = {
import c.universe.Apply;
(null: Any) match {
case c.universe.Apply.unapply(<unapply-selector>) <unapply>
((fn @ _), (args @ _)) => fn
}
}

There is a warning with the second case, but the nature of the warning
is not super clear right now.

Eugene Burmako

unread,
Aug 29, 2012, 4:41:47 PM8/29/12
to scala-l...@googlegroups.com

Oh! I wonder if it is possible to pull the class tag in automatically like it is done for companions.

Reply all
Reply to author
Forward
0 new messages