Skip to content

changelog for reflection and macros in 2.11.0 #310

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

Merged
merged 1 commit into from
Mar 4, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion overviews/macros/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ disqus: true

partof: macros
num: 9
outof: 11
outof: 12
languages: [ja]
---
<span class="label important" style="float: right;">MACRO PARADISE</span>
Expand Down
182 changes: 182 additions & 0 deletions overviews/macros/changelog211.md

Large diffs are not rendered by default.

86 changes: 1 addition & 85 deletions overviews/macros/quasiquotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,88 +20,4 @@ to use them with vanilla 2.10.x.
Neither your code that uses quasiquotes from macro paradise, nor the users of such code will need to have macro paradise
on their classpath at runtime.

## Intuition

Consider an `async` [macro annotation](/overviews/macros/annotations.html), which takes a class or an object and duplicates their methods with asynchronous counterparts wrapped in `future`.

@async
class D {
def x = 2
// def asyncX = future { 2 }
}

val d = new D
d.asyncX onComplete {
case Success(x) => println(x)
case Failure(_) => println("failed")
}

An implementation of such a macro might look as the code at the snippet below. This routine - acquire, destructure, wrap in generated code, restructure again - is quite familiar to macro writers.

case ClassDef(_, _, _, Template(_, _, defs)) =>
val defs1 = defs collect {
case DefDef(mods, name, tparams, vparamss, tpt, body) =>
val tpt1 = if (tpt.isEmpty) tpt else AppliedTypeTree(
Ident(newTermName("Future")), List(tpt))
val body1 = Apply(
Ident(newTermName("future")), List(body))
val name1 = newTermName("async" + name.capitalize)
DefDef(mods, name1, tparams, vparamss, tpt1, body1)
}
Template(Nil, emptyValDef, defs ::: defs1)

However even seasoned macro writers will admit that this code, even though it's quite simple, is exceedingly verbose, requiring one to understand the details internal representation of code snippets, e.g. the difference between `AppliedTypeTree` and `Apply`. Quasiquotes provide a neat domain-specific language that represents parameterized Scala snippets with Scala:

val q"class $name extends Liftable { ..$body }" = tree

val newdefs = body collect {
case q"def $name[..$tparams](...$vparamss): $tpt = $body" =>
val tpt1 = if (tpt.isEmpty) tpt else tq"Future[$tpt]"
val name1 = newTermName("async" + name.capitalize)
q"def $name1[..$tparams](...$vparamss): $tpt1 = future { $body }"
}

q"class $name extends AnyRef { ..${body ++ newdefs} }"

At the moment quasiquotes suffer from [SI-6842](https://issues.scala-lang.org/browse/SI-6842), which doesn't let one write the code as concisely as mentioned above. A [series of casts](https://gist.github.com/7ab617d054f28d68901b) has to be applied to get things working.

## Details

Quasiquotes are implemented as a part of the `scala.reflect.api.Universe` cake, which means that it is enough to do `import c.universe._` to use quasiquotes in macros. Exposed API provides `q`, `tq`, `cq` and `pq` [string interpolators](/overviews/core/string-interpolation.html) (corresponding to term and type quasiquotes), which support both construction and deconstruction, i.e. can be used both in normal code and on the left-hand side of a pattern case.

| Flavor | Works with | Construction | Deconstruction |
|--------|------------|-----------------------|-------------------------------|
| `q` | Term trees | `q"future{ $body }"` | `case q"future{ $body }" =>` |
| `tq` | Type trees | `tq"Future[$t]"` | `case tq"Future[$t]" =>` |
| `cq` | Cases | `cq"x => x"` | `case cq"$pat => ${_}" =>` |
| `pq` | Patterns | `pq"xs @ (hd :: tl)"` | `case pq"$id @ ${_}" =>` |

Unlike regular string interpolators, quasiquotes support multiple flavors of splices in order to distinguish between inserting/extracting single trees, lists of trees and lists of lists of trees. Mismatching cardinalities of splicees and splice operators results in a compile-time error.

scala> val name = TypeName("C")
name: reflect.runtime.universe.TypeName = C

scala> val q"class $name1" = q"class $name"
name1: reflect.runtime.universe.Name = C

scala> val args = List(Literal(Constant(2)))
args: List[reflect.runtime.universe.Literal] = List(2)

scala> val q"foo(..$args1)" = q"foo(..$args)"
args1: List[reflect.runtime.universe.Tree] = List(2)

scala> val argss = List(List(Literal(Constant(2))), List(Literal(Constant(3))))
argss: List[List[reflect.runtime.universe.Literal]] = List(List(2), List(3))

scala> val q"foo(...$argss1)" = q"foo(...$argss)"
argss1: List[List[reflect.runtime.universe.Tree]] = List(List(2), List(3))

## Tips and tricks

### Liftable

To simplify splicing of non-trees, quasiquotes provide the `Liftable` type class, which defines how values are transformed into trees when spliced in. We provide instances of `Liftable` for primitives and strings, which wrap those in `Literal(Constant(...))`. You might want to define your own instances for simple case classes and lists.

trait Liftable[T] {
def apply(universe: api.Universe, value: T): universe.Tree
}
<span class="label success">NEW</span> There's a new, work-in-progress quasiquote guide for Scala 2.11.0 that lives at [http://den.sh/quasiquotes.html](http://den.sh/quasiquotes.html). Behavior of quasiquotes in macro paradise for 2.10.x might differ from what's described in the guide, but that's something that we plan to fix in paradise 2.0.0-final somewhen around the final release of Scala 2.11.0.
2 changes: 1 addition & 1 deletion overviews/reflection/annotations-names-scopes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ disqus: true

partof: reflection
num: 4
outof: 6
outof: 7
languages: [ja]
---

Expand Down
14 changes: 14 additions & 0 deletions overviews/reflection/changelog211.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
layout: overview-large
title: Changes in Scala 2.11

partof: reflection
num: 7
outof: 7
---

<span class="label important" style="float: right;">EXPERIMENTAL</span>

**Eugene Burmako**

The page lives at [/overviews/macros/changelog211.html](/overviews/macros/changelog211.html).
2 changes: 1 addition & 1 deletion overviews/reflection/environment-universes-mirrors.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ disqus: true

partof: reflection
num: 2
outof: 6
outof: 7
languages: [ja]
---

Expand Down
4 changes: 2 additions & 2 deletions overviews/reflection/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: Overview

partof: reflection
num: 1
outof: 6
outof: 7
languages: [ja]
---

Expand Down Expand Up @@ -343,4 +343,4 @@ For more details, see the section of this guide on
[Mirrors]({{ site.baseurl}}/overviews/reflection/environment-universes-mirrors.html),
or the
[Mirrors API docs](http://www.scala-lang.org/api/{{ site.scala-version}}/scala/reflect/api/Mirrors.html)
in package `scala.reflect.api`.
in package `scala.reflect.api`.
2 changes: 1 addition & 1 deletion overviews/reflection/symbols-trees-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ disqus: true

partof: reflection
num: 3
outof: 6
outof: 7
languages: [ja]
---

Expand Down
2 changes: 1 addition & 1 deletion overviews/reflection/thread-safety.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ disqus: true

partof: reflection
num: 6
outof: 6
outof: 7
languages: [ja]
---

Expand Down
2 changes: 1 addition & 1 deletion overviews/reflection/typetags-manifests.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ disqus: true

partof: reflection
num: 5
outof: 6
outof: 7
languages: [ja]
---

Expand Down