2

I'm learning implicit methods in Scala. For instance consider the following test code:

object Test{
  def main(args: Array[String]) = {
    implicit val f: Int => String = (_: Int).toString + "sdgfdfsg"
    val Ext(i) = 10
    println(i)
  }
}


object Ext{
  def unapply(i: Int)(implicit f: Int => String): Option[String] = Some(f(i))
}

This code works as expected. But the thing that is not clear to me is why it works. So I read about Scala compiler phases and figured out that all desugaring is performed during the first phase:

parser   1  parse source into ASTs, perform simple desugaring

But what is the order of desugaring? It seems in the example the

val Ext(i) = 10

was first desugared to

val i = Ext.unapply(10)

and then compiler found the implicit value implicit val f: Int => String = (_: Int).toString + "sdgfdfsg" and the final desugared version is

val i = Ext.unapply(10)(f)

Why are implicits desugared later? Or how is it working?

1 Answer 1

2

The implicits are not "desugared". The word "desugar" stems from the expression "syntactic sugar". Note the "syntactic" part in "syntactic sugar". It means that this kind of transformation can take place on the very low syntactic level. For example, in order to desugar

val Ext(i) = ten

into something like

val i = Ext.unapply(ten).get

you don't have to know anything about the types of Ext, or ten, or i. You don't even have to know whether those symbols exist in scope at all. You take the raw syntactic snippets, and reorder them a little bit, that's all.

(I added the get because otherwise the types don't match, the actual desugared code as printed by scala -print is significantly scarier)


The search for implicits is very different. It crucially depends on the fact that all symbols and method signatures have been resolved, and that all types of all subexpressions have been derived [footnote 1]. This is because:

  • The symbols must be resolved because otherwise the compiler wouldn't even know that the method unapply on object Ext needs additional implicit arguments.
  • The types must be known, because otherwise it wouldn't know what type of implicit to search for.

Both kinds of information are not present in the raw syntactic structure of the program, and have first to be reconstructed in the later phases. That's why the implicit resolution has to come after the purely syntactic desugaring.

[footnote 1] That's an oversimplification: the typechecker must somehow deduce more information after some of the implicits have been inserted, so it seems that those phases must be intertwined.

Sign up to request clarification or add additional context in comments.

3 Comments

I just noticed that 5 translate match expressions. It means pattern matching is not a simple sugar? Very interesting...
Anyway scala -print makes it much more clear. Thank you.
@SomeName Well, for match expressions, you have for example to make exhaustiveness checks. This requires that you know about a whole bunch of sealed traits elsewhere in the code, or even in other imported libraries. So it can't be purely syntactic. Maybe this step is more about rewriting match-case into simpler low-level switch-statements, utilizing certain nice properties of case classes which allow optimization. I don't know. Would have to look it up myself.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.