Skip to content

Commit 3535079

Browse files
committed
initial docs on extractor macros
1 parent 79a9398 commit 3535079

File tree

6 files changed

+94
-6
lines changed

6 files changed

+94
-6
lines changed

overviews/macros/annotations.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ title: Macro Annotations
55
disqus: true
66

77
partof: macros
8-
num: 8
9-
outof: 10
8+
num: 9
9+
outof: 11
1010
languages: [ja]
1111
---
1212
<span class="label important" style="float: right;">MACRO PARADISE</span>

overviews/macros/extractors.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
---
2+
layout: overview-large
3+
title: Extractor Macros
4+
5+
disqus: true
6+
7+
partof: macros
8+
num: 6
9+
---
10+
<span class="label warning" style="float: right;">EXPERIMENTAL</span>
11+
12+
**Eugene Burmako**
13+
14+
Extractor macros are shipped with the recent milestone builds of Scala 2.11, starting from 2.11.0-M5, enabled by name-based extractors introduced by Paul Phillips in Scala 2.11.0-M5. Extractor macros are not available in Scala 2.10.x or in macro paradise. Follow the instructions at [http://www.scala-lang.org/download/](http://www.scala-lang.org/download/) to download and use the latest milestone of 2.11.
15+
16+
### The pattern
17+
18+
In a nutshell, given an unapply method (for simplicity, in this
19+
example the scrutinee is of a concrete type, but it's also possible
20+
to have the extractor be polymorphic, as demonstrated in the tests):
21+
22+
def unapply(x: SomeType) = ???
23+
24+
One can write a macro that generates extraction signatures for unapply
25+
on per-call basis, using the target of the calls (`c.prefix`) and the type
26+
of the scrutinee (that comes with `x`), and then communicate these signatures
27+
to the typechecker.
28+
29+
For example, here's how one can define a macro that simply passes
30+
the scrutinee back to the pattern match (for information on how to
31+
express signatures that involve multiple extractees, visit
32+
[scala/scala#2848](https://github.com/scala/scala/pull/2848)).
33+
34+
def unapply(x: SomeType) = macro impl
35+
def impl(c: Context)(x: c.Tree) = {
36+
q"""
37+
new {
38+
class Match(x: SomeType) {
39+
def isEmpty = false
40+
def get = x
41+
}
42+
def unapply(x: SomeType) = new Match(x)
43+
}.unapply($x)
44+
"""
45+
}
46+
47+
In addition to the matcher, which implements domain-specific
48+
matching logic, there's quite a bit of boilerplate here, but
49+
every part of it looks necessary to arrange a non-frustrating dialogue
50+
with the typer. Maybe something better can be done in this department,
51+
but I can't see how, without introducing modifications to the typechecker.
52+
53+
Even though the pattern uses structural types, somehow no reflective calls
54+
are being generated (as verified by `-Xlog-reflective-calls` and then
55+
by manual examination of the produced code). That's a mystery to me, but
56+
that's also good news, since that means that extractor macros aren't
57+
going to induce performance penalties.
58+
59+
Almost. Unfortunately, I couldn't turn matchers into value classes
60+
because one can't declare value classes local. Nevertheless,
61+
I'm leaving a canary in place ([neg/t5903e](https://github.com/scala/scala/blob/00624a39ed84c3fd245dd9df7454d4cec4399e13/test/files/neg/t5903e/Macros_1.scala#L1)) that will let us know
62+
once this restriction is lifted.
63+
64+
### Use cases
65+
66+
In particular, the pattern can be used to implement shapeshifting
67+
pattern matchers for string interpolators without resorting to dirty
68+
tricks. For example, quasiquote unapplications can be unhardcoded now:
69+
70+
def doTypedApply(tree: Tree, fun0: Tree, args: List[Tree], ...) = {
71+
...
72+
fun.tpe match {
73+
case ExtractorType(unapply) if mode.inPatternMode =>
74+
// this hardcode in Typers.scala is no longer necessary
75+
if (unapply == QuasiquoteClass_api_unapply) macroExpandUnapply(...)
76+
else doTypedUnapply(tree, fun0, fun, args, mode, pt)
77+
}
78+
}
79+
80+
Rough implementation strategy here would involve writing an extractor
81+
macro that destructures `c.prefix`, analyzes parts of `StringContext` and
82+
then generates an appropriate matcher as outlined above.
83+
84+
Follow our test cases at [run/t5903a](https://github.com/scala/scala/tree/00624a39ed84c3fd245dd9df7454d4cec4399e13/test/files/run/t5903a),
85+
[run/t5903b](https://github.com/scala/scala/tree/00624a39ed84c3fd245dd9df7454d4cec4399e13/test/files/run/t5903b),
86+
[run/t5903c](https://github.com/scala/scala/tree/00624a39ed84c3fd245dd9df7454d4cec4399e13/test/files/run/t5903c),
87+
[run/t5903d](https://github.com/scala/scala/tree/00624a39ed84c3fd245dd9df7454d4cec4399e13/test/files/run/t5903d) to see implementations
88+
of this and other use cases for extractor macros.

overviews/macros/paradise.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ title: Macro Paradise
55
disqus: true
66

77
partof: macros
8-
num: 9
8+
num: 10
99
languages: [ja]
1010
---
1111
<span class="label success" style="float: right;">NEW</span>

overviews/macros/quasiquotes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ title: Quasiquotes
55
disqus: true
66

77
partof: macros
8-
num: 7
8+
num: 8
99
languages: [ja]
1010
---
1111
<span class="label warning" style="float: right;">EXPERIMENTAL</span>

overviews/macros/roadmap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ title: Roadmap
55
disqus: true
66

77
partof: macros
8-
num: 10
8+
num: 11
99
languages: [ja]
1010
---
1111

overviews/macros/typeproviders.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ title: Type Providers
55
disqus: true
66

77
partof: macros
8-
num: 6
8+
num: 7
99
languages: [ja]
1010
---
1111
<span class="label warning" style="float: right;">EXPERIMENTAL</span>

0 commit comments

Comments
 (0)