Backstage JavaMaking a Difference in Metaprogramming
Zachary Palmer and Scott F. Smith
The Johns Hopkins University
October 27, 2011
Difference-Based Metaprogramming
• Introduction to Metaprogramming
• Compile-Time Metaprogramming in Java
• Traditional Metaprogramming Model
• Difference-Based Metaprogramming Model
Difference-Based Metaprogramming
• Introduction to Metaprogramming
• Compile-Time Metaprogramming in Java
• Traditional Metaprogramming Model
• Difference-Based Metaprogramming Model
Difference-Based Metaprogramming
• Introduction to Metaprogramming
• Compile-Time Metaprogramming in Java
• Traditional Metaprogramming Model
• Difference-Based Metaprogramming Model
Difference-Based Metaprogramming
• Introduction to Metaprogramming
• Compile-Time Metaprogramming in Java
• Traditional Metaprogramming Model
• Difference-Based Metaprogramming Model
Metaprogramming• Programs input data and output data.
Input ρ Output
• Metaprograms input programs (or programfragments) and output the same.
ρ φ ρ′
Metaprogramming• Programs input data and output data.
Input ρ Output
• Metaprograms input programs (or programfragments) and output the same.
ρ φ ρ′
Examples of Metaprogramming
• C Macros
• C++ Templates
• LISP Macros
• Template Haskell
• MetaOCaml
• Stratego
• Groovy
• etc. etc.
Classifying Metaprogramming
• When is it run?• Compile-time (static)• Runtime (dynamic)
• How are programs represented?• Textually (strings)• Lexically (tokens)• Structurally (ASTs)• Semantically (various structures)
• Which language is used to metaprogram?• Same language (homogenous)• Different language (heterogeneous)
from Accomplishments and Research Challenges in Metaprogramming (Tim Sheard)
Classifying Metaprogramming
• When is it run?• Compile-time (static)• Runtime (dynamic)
• How are programs represented?• Textually (strings)• Lexically (tokens)• Structurally (ASTs)• Semantically (various structures)
• Which language is used to metaprogram?• Same language (homogenous)• Different language (heterogeneous)
from Accomplishments and Research Challenges in Metaprogramming (Tim Sheard)
Template Haskell Example
$(
let mkExp n v =
if n == 0
then [| 1 |]
else [| $(v) * $(mkExp (n-1) v) |]
in
let f n =
let funNm = mkName ("exp" ++ (show n)) in
let params = [varP (mkName "x")] in
funD funNm $ [clause params
(normalB $ mkExp n (varE $ mkName "x")) []]
in
mapM f [2..50]
)
Template Haskell Example
exp2 x = x * x
exp3 x = x * x * x
exp4 x = x * x * x * x
exp5 x = x * x * x * x * x
exp6 x = x * x * x * x * x * x...
......
exp50 x =
50︷ ︸︸ ︷x * x * . . . * x * x
Template Haskell
• Programmatic code generation
• Literal syntax for AST construction
• Functional programming style
• Very limited ability to inspect environment
Template Haskell
• Programmatic code generation
• Literal syntax for AST construction
• Functional programming style
• Very limited ability to inspect environment
Template Haskell
• Programmatic code generation
• Literal syntax for AST construction
• Functional programming style
• Very limited ability to inspect environment
Template Haskell
• Programmatic code generation
• Literal syntax for AST construction
• Functional programming style
• Very limited ability to inspect environment
Template Java?public class Location {
private int x;
public int getX() { return this.x; }
public void setX(int x) { this.x = x; }
private int y;
public int getY() { return this.y; }
public void setY(int y) { this.y = y; }
public Location(int x, int y) {
this.x = x;
this.y = y;
}
public String toString() {
return "("+this.x+","+this.y+")";
}
}
Template Java?public class Location {
private int x;
public int getX() { return this.x; }
public void setX(int x) { this.x = x; }
private int y;
public int getY() { return this.y; }
public void setY(int y) { this.y = y; }
public Location(int x, int y) {
this.x = x;
this.y = y;
}
public String toString() {
return "("+this.x+","+this.y+")";
}
}
Template Java?public class Location {
$( property( [|private int x|] )
private int y;
public int getY() { return this.y; }
public void setY(int y) { this.y = y; }
public Location(int x, int y) {
this.x = x;
this.y = y;
}
public String toString() {
return "("+this.x+","+this.y+")";
}
}
Template Java?public class Location {
$( property( [|private int x|] )
private int y;
public int getY() { return this.y; }
public void setY(int y) { this.y = y; }
public Location(int x, int y) {
this.x = x;
this.y = y;
}
public String toString() {
return "("+this.x+","+this.y+")";
}
}
Template Java?public class Location {
$( property( [|private int x|] )
$( property( [|private int y|] )
public Location(int x, int y) {
this.x = x;
this.y = y;
}
public String toString() {
return "("+this.x+","+this.y+")";
}
}
Template Java?public class Location {
$( property( [|private int x|] )
$( property( [|private int y|] )
public Location(int x, int y) {
this.x = x;
this.y = y;
}
public String toString() {
return "("+this.x+","+this.y+")";
}
}
Template Java?public class Location {
$( property( [|private int x|] )
$( property( [|private int y|] )
$( makePropertyConstructor(
[|int x|], [|int y|]) )
public String toString() {
return "("+this.x+","+this.y+")";
}
}
Template Java?public class Location {
$( property( [|private int x|] )
$( property( [|private int y|] )
$( makePropertyConstructor(
[|int x|], [|int y|]) )
public String toString() {
return "("+this.x+","+this.y+")";
}
}
• Metaprograms can’t react to surrounding code• Metaprogrammers compensate by duplicating
information• Functional metaprogramming in a declarative
object-oriented language
Template Java?public class Location {
$( property( [|private int x|] )
$( property( [|private int y|] )
$( makePropertyConstructor(
[|int x|], [|int y|]) )
public String toString() {
return "("+this.x+","+this.y+")";
}
}
• Metaprograms can’t react to surrounding code
• Metaprogrammers compensate by duplicatinginformation
• Functional metaprogramming in a declarativeobject-oriented language
Template Java?public class Location {
$( property( [|private int x|] )
$( property( [|private int y|] )
$( makePropertyConstructor(
[|int x|], [|int y|]) )
public String toString() {
return "("+this.x+","+this.y+")";
}
}
• Metaprograms can’t react to surrounding code• Metaprogrammers compensate by duplicating
information
• Functional metaprogramming in a declarativeobject-oriented language
Template Java?public class Location {
$( property( [|private int x|] )
$( property( [|private int y|] )
$( makePropertyConstructor(
[|int x|], [|int y|]) )
public String toString() {
return "("+this.x+","+this.y+")";
}
}
• Metaprograms can’t react to surrounding code• Metaprogrammers compensate by duplicating
information• Functional metaprogramming in a declarative
object-oriented language
What Do We Want?
• Object-oriented, declarative metaprogrammingstyle
• Awareness of surrounding code
• Modular, independent metaprograms
What Do We Want?
• Object-oriented, declarative metaprogrammingstyle
• Awareness of surrounding code
• Modular, independent metaprograms
What Do We Want?
• Object-oriented, declarative metaprogrammingstyle
• Awareness of surrounding code
• Modular, independent metaprograms
Backstage Java
How about some of this?
@@GenerateConstructorFromProperties
public class Location {
@@Property private int x;
@@Property private int y;
public String toString() {
return "("+this.x+","+this.y+")";
}
}
Harder than it looks...
Backstage Java
How about some of this?
@@GenerateConstructorFromProperties
public class Location {
@@Property private int x;
@@Property private int y;
public String toString() {
return "("+this.x+","+this.y+")";
}
}
Harder than it looks...
Traditional Metaprogramming
• Metaprograms are a series of programtransformations
• Each available transformation occurs exactlyonce
• True even for embedded syntax
Traditional Metaprogramming
• Metaprograms are a series of programtransformations
• Each available transformation occurs exactlyonce
• True even for embedded syntax
Traditional Metaprogramming
• Metaprograms are a series of programtransformations
• Each available transformation occurs exactlyonce
• True even for embedded syntax
Ambiguity in Metaprogramming
Assuming three transformations φ1, φ2, φ3...
ρ
? ? ? ? ? ?
OpenJava, Groovy
Ambiguity in Metaprogramming
Assuming three transformations φ1, φ2, φ3...
ρ
? ? ? ? ? ?
OpenJava, Groovy
Necessary Commutation Solution
Requiring that φi ◦ φj = φj ◦ φi for all i and j
ρ
ρ′
Template Haskell, MetaOCaml, LISP, ...
Necessary Commutation Solution
Requiring that φi ◦ φj = φj ◦ φi for all i and j
ρ
ρ′
Template Haskell, MetaOCaml, LISP, ...
Hybrid Solution
Suppose that φ1 and φ2 commute.Suppose that φ3 must occur after them.
ρ
Backstage Java*
Hybrid Solution
Suppose that φ1 and φ2 commute.
Suppose that φ3 must occur after them.
ρ
Backstage Java*
Hybrid Solution
Suppose that φ1 and φ2 commute.
Suppose that φ3 must occur after them.
ρ
◦
◦
Backstage Java*
Hybrid Solution
Suppose that φ1 and φ2 commute.Suppose that φ3 must occur after them.
ρ
◦
◦
Backstage Java*
Hybrid Solution
Suppose that φ1 and φ2 commute.Suppose that φ3 must occur after them.
ρ
◦
◦
Backstage Java*
Hybrid Solution
Suppose that φ1 and φ2 commute.Suppose that φ3 must occur after them.
ρ
◦
◦
Backstage Java*
Hybrid Solution
Suppose that φ1 and φ2 commute.Suppose that φ3 must occur after them.
ρ
◦
◦
Backstage Java*
Hybrid Solution
Suppose that φ1 and φ2 commute.Suppose that φ3 must occur after them.
ρ
◦
◦
Backstage Java*
Commuting Transformations
How do we tell if φ1 and φ2 commute?
◦?
Determining whether or not two arbitrarytransformations commute is undecidable!
Commuting Transformations
How do we tell if φ1 and φ2 commute?
◦?
Determining whether or not two arbitrarytransformations commute is undecidable!
Commuting Transformations
How do we tell if φ1 and φ2 commute?
◦?
Determining whether or not two arbitrarytransformations commute is undecidable!
Difference-Based MetaprogrammingTreat metaprograms as transformation generators:
φ(ρ) = δ̄
Jδ̄K(ρ) = ρ′
Difference-Based MetaprogrammingTreat metaprograms as transformation generators:
φ(ρ) = δ̄
Jδ̄K(ρ) = ρ′
Difference-Based MetaprogrammingTreat metaprograms as transformation generators:
φ(ρ) = δ̄
Jδ̄K(ρ) = ρ′
Difference-Based MetaprogrammingTreat metaprograms as transformation generators:
φ(ρ) = δ̄
Jδ̄K(ρ) = ρ′
• Language of δ̄ is not Turing-complete
• Each δ̄ is generated on a case-by-case basis
• No practically significant loss of expressiveness
Difference-Based MetaprogrammingTreat metaprograms as transformation generators:
φ(ρ) = δ̄
Jδ̄K(ρ) = ρ′
• Language of δ̄ is not Turing-complete
• Each δ̄ is generated on a case-by-case basis
• No practically significant loss of expressiveness
Difference-Based MetaprogrammingTreat metaprograms as transformation generators:
φ(ρ) = δ̄
Jδ̄K(ρ) = ρ′
• Language of δ̄ is not Turing-complete
• Each δ̄ is generated on a case-by-case basis
• No practically significant loss of expressiveness
Difference-Based MetaprogrammingTreat metaprograms as transformation generators:
φ(ρ) = δ̄
Jδ̄K(ρ) = ρ′
δ̄ can express:
• Creation of a node
• Assignment to a node property
• Additions before or after an element in a list
• Removal of an element from a list
Difference-Based MetaprogrammingTreat metaprograms as transformation generators:
φ(ρ) = δ̄
Jδ̄K(ρ) = ρ′
δ̄ can express:
• Creation of a node
• Assignment to a node property
• Additions before or after an element in a list
• Removal of an element from a list
Difference-Based MetaprogrammingTreat metaprograms as transformation generators:
φ(ρ) = δ̄
Jδ̄K(ρ) = ρ′
δ̄ can express:
• Creation of a node
• Assignment to a node property
• Additions before or after an element in a list
• Removal of an element from a list
Difference-Based MetaprogrammingTreat metaprograms as transformation generators:
φ(ρ) = δ̄
Jδ̄K(ρ) = ρ′
δ̄ can express:
• Creation of a node
• Assignment to a node property
• Additions before or after an element in a list
• Removal of an element from a list
Difference-Based MetaprogrammingTreat metaprograms as transformation generators:
φ(ρ) = δ̄
Jδ̄K(ρ) = ρ′
Now, prove commutation over pairs of Jδ̄K.
◦
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
Difference-Based MetaprogrammingTreat metaprograms as transformation generators:
φ(ρ) = δ̄
Jδ̄K(ρ) = ρ′
Now, prove commutation over pairs of Jδ̄K.
◦
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
A Simple BSJ Examplepublic class Example {
public static void main(String[] arg) {
[:
BlockStatementListNode list = context.getAnchor().
getNearestAncestorOfType(
BlockStatementListNode.class);
list.addFirst(
<:System.out.println("Hello, world!");:>);
:]
[:
BlockStatementListNode list = context.getAnchor().
getNearestAncestorOfType(
BlockStatementListNode.class);
list.addLast(
<:System.out.println("How are you?");:>);
:]
}
}
A Simple Examplepublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
M1
M2
System.out.println("How are you?");
}
}
• Replace metaprograms with anchors
• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” last)
• Prove that δ̄1 and δ̄2 commute.
• Execute δ̄1 and δ̄2 in some order.
A Simple Examplepublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
M1
M2
System.out.println("How are you?");
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” last)
• Prove that δ̄1 and δ̄2 commute.
• Execute δ̄1 and δ̄2 in some order.
A Simple Examplepublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
M1
M2
System.out.println("How are you?");
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)
• φ2(ρ) = δ̄2 (“How are you?” last)
• Prove that δ̄1 and δ̄2 commute.
• Execute δ̄1 and δ̄2 in some order.
A Simple Examplepublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
M1
M2
System.out.println("How are you?");
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” last)
• Prove that δ̄1 and δ̄2 commute.
• Execute δ̄1 and δ̄2 in some order.
A Simple Examplepublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
M1
M2
System.out.println("How are you?");
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” last)
• Prove that δ̄1 and δ̄2 commute.
• Execute δ̄1 and δ̄2 in some order.
A Simple Examplepublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
M1
M2
System.out.println("How are you?");
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” last)
• Prove that δ̄1 and δ̄2 commute.
• Execute δ̄1 and δ̄2 in some order.
A Simple Examplepublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
M1
M2
System.out.println("How are you?");
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” last)
• Prove that δ̄1 and δ̄2 commute.
• Execute δ̄1 and δ̄2 in some order.
A Simple Examplepublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
M1
M2
System.out.println("How are you?");
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” last)
• Prove that δ̄1 and δ̄2 commute.
• Execute δ̄1 and δ̄2 in some order.
A Simple Examplepublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
M1
M2
System.out.println("How are you?");
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” last)
• Prove that δ̄1 and δ̄2 commute.
• Execute δ̄1 and δ̄2 in some order.
A Simple Examplepublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
M1
M2
System.out.println("How are you?");
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” last)
• Prove that δ̄1 and δ̄2 commute.
• Execute δ̄1 and δ̄2 in some order.
A Simple Examplepublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
M1
M2
System.out.println("How are you?");
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” last)
• Prove that δ̄1 and δ̄2 commute.
• Execute δ̄1 and δ̄2 in some order.
A Simple Examplepublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
;
;
System.out.println("How are you?");
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” last)
• Prove that δ̄1 and δ̄2 commute.
• Execute δ̄1 and δ̄2 in some order.
An Example of Conflictpublic class Example {
public static void main(String[] arg) {
[:
BlockStatementListNode list = context.getAnchor().
getNearestAncestorOfType(
BlockStatementListNode.class);
list.addFirst(
<:System.out.println("Hello, world!");:>);
:]
[:
BlockStatementListNode list = context.getAnchor().
getNearestAncestorOfType(
BlockStatementListNode.class);
list. addFirst (
<:System.out.println("How are you?");:>);
:]
}
}
An Example of Conflictpublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
System.out.println("Hello, world!");
M1
M2
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” first)
• Now, δ̄1 and δ̄2 do not commute!
• But we can detect this!
An Example of Conflictpublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
System.out.println("Hello, world!");
M1
M2
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” first)
• Now, δ̄1 and δ̄2 do not commute!
• But we can detect this!
An Example of Conflictpublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
System.out.println("How are you?");
M1
M2
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” first)
• Now, δ̄1 and δ̄2 do not commute!
• But we can detect this!
An Example of Conflictpublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
System.out.println("How are you?");
M1
M2
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” first)
• Now, δ̄1 and δ̄2 do not commute!
• But we can detect this!
An Example of Conflictpublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
System.out.println("Hello, world!");
M1
M2
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” first)
• Now, δ̄1 and δ̄2 do not commute!
• But we can detect this!
An Example of Conflictpublic class Example {
public static void main(String[] arg) {
System.out.println("Hello, world!");
System.out.println("Hello, world!");
M1
M2
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” first)
• Now, δ̄1 and δ̄2 do not commute!
• But we can detect this!
An Example of Conflictpublic class Example {
public static void main(String[] arg) {
System.out.println("How are you?");
System.out.println("Hello, world!");
M1
M2
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” first)
• Now, δ̄1 and δ̄2 do not commute!
• But we can detect this!
An Example of Conflictpublic class Example {
public static void main(String[] arg) {
System.out.println("How are you?");
System.out.println("Hello, world!");
;
;
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” first)
• Now, δ̄1 and δ̄2 do not commute!
• But we can detect this!
An Example of Conflictpublic class Example {
public static void main(String[] arg) {
System.out.println("How are you?");
System.out.println("Hello, world!");
;
;
}
}
• Replace metaprograms with anchors• Run each metaprogram to collect its changes
• φ1(ρ) = δ̄1 (“Hello, world!” first)• φ2(ρ) = δ̄2 (“How are you?” first)
• Now, δ̄1 and δ̄2 do not commute!
• But we can detect this!
Conflict DetectionRecord Node Creation Ruleη 7→ v̂ /∈ ρ ρJη 7→ {l 7→ v̂}K⇒ ρ
′
(+R η(l = v̂)) ρ⇒ ρ′
List Node Creation Ruleη 7→ v̂ /∈ ρ
ρJη 7→ [(.,M, ∅), (/,M, ∅)]K⇒ ρ′
(M � +Lη) ρ⇒ ρ′
Record Assignment Ruleη 7→ R ∈ ρ ρJη 7→ RJl 7→ v̂KK⇒ ρ
′
(η.l ← v̂) ρ⇒ ρ′
List Add Before RuleMη3 6= . η1 7→ L ∈ ρ
◦η3 = Σ(Mη3,M,L) L = [◦η′, ◦η3,
◦η′′]
L′ = [◦η′, (η2,M, ∅), ◦η3,◦η′′]
ρJη1 7→ L′K⇒ ρ
′
(M � η1 : η2 " Mη3) ρ⇒ ρ
′
List Add After RuleMη3 6= / η1 7→ L ∈ ρ
◦η3 = Σ(Mη3,M,L) L = [◦η′, ◦η3,
◦η′′]
L′ = [◦η′, ◦η3, (η2,M, ∅), ◦η′′]
ρJη1 7→ L′K⇒ ρ
′
(M � η1 :Mη3 # η2) ρ⇒ ρ
′
List Remove Ruleη1 7→ L ∈ ρ◦η2 = (η2,M
′,S) = Σ(η2,M,L)
L = [◦η′, ◦η2,◦η′′]
L′ = [◦η′, (η2,M′,S ∪ {M}), ◦η′′]
ρJη1 7→ L′K⇒ ρ
′
(M � η1 : ↓ η2) ρ⇒ ρ′
Recursive Application Ruleδ′ e ⇒ ρ δ ρ⇒ ρ
′
δ (δ′ e)⇒ ρ′
Value Rule
v̂ ⇒ v̂
Record Assignment Conflict Rulev̂ 6= v̂′
η.l ← v̂ = η.l ← v̂′
Add Before Conflict Ruleω(η2) ω(η′2)
η1 : η2 " Mη3 = η1 : η′2 " M
η3
Add After Conflict Ruleω(η2) ω(η′2)
η1 :Mη3 # η2 = η1 :
Mη3 # η
′2
Unordered Creation Conflict Ruleδ = +R η(l 7→ v̂) ∨ δ = +Lη η ∈ δ′
δ = δ′
Conflict DetectionRecord Node Creation Ruleη 7→ v̂ /∈ ρ ρJη 7→ {l 7→ v̂}K⇒ ρ
′
(+R η(l = v̂)) ρ⇒ ρ′
List Node Creation Ruleη 7→ v̂ /∈ ρ
ρJη 7→ [(.,M, ∅), (/,M, ∅)]K⇒ ρ′
(M � +Lη) ρ⇒ ρ′
Record Assignment Ruleη 7→ R ∈ ρ ρJη 7→ RJl 7→ v̂KK⇒ ρ
′
(η.l ← v̂) ρ⇒ ρ′
List Add Before RuleMη3 6= . η1 7→ L ∈ ρ
◦η3 = Σ(Mη3,M,L) L = [◦η′, ◦η3,
◦η′′]
L′ = [◦η′, (η2,M, ∅), ◦η3,◦η′′]
ρJη1 7→ L′K⇒ ρ
′
(M � η1 : η2 " Mη3) ρ⇒ ρ
′
List Add After RuleMη3 6= / η1 7→ L ∈ ρ
◦η3 = Σ(Mη3,M,L) L = [◦η′, ◦η3,
◦η′′]
L′ = [◦η′, ◦η3, (η2,M, ∅), ◦η′′]
ρJη1 7→ L′K⇒ ρ
′
(M � η1 :Mη3 # η2) ρ⇒ ρ
′
List Remove Ruleη1 7→ L ∈ ρ◦η2 = (η2,M
′,S) = Σ(η2,M,L)
L = [◦η′, ◦η2,◦η′′]
L′ = [◦η′, (η2,M′,S ∪ {M}), ◦η′′]
ρJη1 7→ L′K⇒ ρ
′
(M � η1 : ↓ η2) ρ⇒ ρ′
Recursive Application Ruleδ′ e ⇒ ρ δ ρ⇒ ρ
′
δ (δ′ e)⇒ ρ′
Value Rule
v̂ ⇒ v̂
Record Assignment Conflict Rulev̂ 6= v̂′
η.l ← v̂ = η.l ← v̂′
Add Before Conflict Ruleω(η2) ω(η′2)
η1 : η2 " Mη3 = η1 : η′2 " M
η3
Add After Conflict Ruleω(η2) ω(η′2)
η1 :Mη3 # η2 = η1 :
Mη3 # η
′2
Unordered Creation Conflict Ruleδ = +R η(l 7→ v̂) ∨ δ = +Lη η ∈ δ′
δ = δ′
Huzzah!
• Metaprogram conflicts are detected at compiletime
• Metaprograms are still aware of theirsurroundings
,
Huzzah!
• Metaprogram conflicts are detected at compiletime
• Metaprograms are still aware of theirsurroundings
,
Huzzah!
• Metaprogram conflicts are detected at compiletime
• Metaprograms are still aware of theirsurroundings
,
Dependenciespublic static void main(String[] arg) {
[:
#depends foo; ← Declare target dependency
BlockStatementListNode list = context.getAnchor().
getNearestAncestorOfType(
BlockStatementListNode.class);
list.addFirst(
<:System.out.println("Hello, world!");:>);
:]
[:
#target foo; ← Declare target membership
BlockStatementListNode list = context.getAnchor().
getNearestAncestorOfType(
BlockStatementListNode.class);
list.addFirst(
<:System.out.println("How are you?");:>);
:]
}
Dependenciespublic static void main(String[] arg) {
[:
#depends foo; ← Declare target dependency
BlockStatementListNode list = context.getAnchor().
getNearestAncestorOfType(
BlockStatementListNode.class);
list.addFirst(
<:System.out.println("Hello, world!");:>);
:]
[:
#target foo; ← Declare target membershipBlockStatementListNode list = context.getAnchor().
getNearestAncestorOfType(
BlockStatementListNode.class);
list.addFirst(
<:System.out.println("How are you?");:>);
:]
}
Dependenciespublic static void main(String[] arg) {
[:
#depends foo; ← Declare target dependencyBlockStatementListNode list = context.getAnchor().
getNearestAncestorOfType(
BlockStatementListNode.class);
list.addFirst(
<:System.out.println("Hello, world!");:>);
:]
[:
#target foo;
← Declare target membership
BlockStatementListNode list = context.getAnchor().
getNearestAncestorOfType(
BlockStatementListNode.class);
list.addFirst(
<:System.out.println("How are you?");:>);
:]
}
Dependenciespublic static void main(String[] arg) {
[:
#depends foo;
← Declare target dependency
BlockStatementListNode list = context.getAnchor().
getNearestAncestorOfType(
BlockStatementListNode.class);
list.addFirst(
<:System.out.println("Hello, world!");:>);
:]
[:
#target foo;
← Declare target membership
BlockStatementListNode list = context.getAnchor().
getNearestAncestorOfType(
BlockStatementListNode.class);
list.addFirst(
<:System.out.println("How are you?");:>);
:]
}
Dependency Graph
M1 M2
foo
• One node per metaprogram
• M2 is a member of target “foo”
• M1 depends on the target “foo”
• Therefore, M1 depends on M2 (M1 M2)
• No more requirement for them to commute!
Dependency Graph
M1 M2
foo
• One node per metaprogram
• M2 is a member of target “foo”
• M1 depends on the target “foo”
• Therefore, M1 depends on M2 (M1 M2)
• No more requirement for them to commute!
Dependency Graph
M1 M2
foo
• One node per metaprogram
• M2 is a member of target “foo”
• M1 depends on the target “foo”
• Therefore, M1 depends on M2 (M1 M2)
• No more requirement for them to commute!
Dependency Graph
M1 M2foo
• One node per metaprogram
• M2 is a member of target “foo”
• M1 depends on the target “foo”
• Therefore, M1 depends on M2 (M1 M2)
• No more requirement for them to commute!
Dependency Graph
M1 M2foo
• One node per metaprogram
• M2 is a member of target “foo”
• M1 depends on the target “foo”
• Therefore, M1 depends on M2 (M1 M2)
• No more requirement for them to commute!
Dependency Graph
M1 M2foo
• One node per metaprogram
• M2 is a member of target “foo”
• M1 depends on the target “foo”
• Therefore, M1 depends on M2 (M1 M2)
• No more requirement for them to commute!
Dependency Graph
M1 M2foo
• One node per metaprogram
• M2 is a member of target “foo”
• M1 depends on the target “foo”
• Therefore, M1 depends on M2 (M1 M2)
• No more requirement for them to commute!
Dependency Graph
M1 M2foo
• One node per metaprogram
• M2 is a member of target “foo”
• M1 depends on the target “foo”
• Therefore, M1 depends on M2 (M1 M2)
• No more requirement for them to commute!
Dependency Graph
M1 M2foo
• One node per metaprogram
• M2 is a member of target “foo”
• M1 depends on the target “foo”
• Therefore, M1 depends on M2 (M1 M2)
• No more requirement for them to commute!
Dependency Graph
M1 a M4 c M6
M2 M3 b M5 M7
/* M1 */ [: #target a; :]
/* M2 */ [: #target a; :]
/* M3 */ [: #target a, b; :]
/* M4 */ [: #target c; #depends a; :]
/* M5 */ [: #target c; #depends b; :]
/* M6 */ [: #depends c; :]
/* M7 */ [: :]
Dependency Graph
M1 a M4 c M6
M2 M3 b M5 M7
• M6 depends on M2 - no obligation to commute
• No path between M5 and M4 - must commute
• No path to M7 - must always commute
• More paths means less obligation to provecommutativity
Dependency Graph
M1 a M4 c M6
M2 M3 b M5 M7
• M6 depends on M2 - no obligation to commute
• No path between M5 and M4 - must commute
• No path to M7 - must always commute
• More paths means less obligation to provecommutativity
Dependency Graph
M1 a M4 c M6
M2 M3 b M5 M7
• M6 depends on M2 - no obligation to commute
• No path between M5 and M4 - must commute
• No path to M7 - must always commute
• More paths means less obligation to provecommutativity
Dependency Graph
M1 a M4 c M6
M2 M3 b M5 M7
• M6 depends on M2 - no obligation to commute
• No path between M5 and M4 - must commute
• No path to M7 - must always commute
• More paths means less obligation to provecommutativity
Meta-Annotations
@@Property private int x;
• Declarative metaprogramming abstraction
• Specifies metaprogram code and dependencies
• Can annotate any declaration or blockstatement
• Allows easy reuse of metaprogrammingconstructs
• Here defined by user class named Property
Meta-Annotations
@@Property private int x;
• Declarative metaprogramming abstraction
• Specifies metaprogram code and dependencies
• Can annotate any declaration or blockstatement
• Allows easy reuse of metaprogrammingconstructs
• Here defined by user class named Property
Meta-Annotations
@@Property private int x;
• Declarative metaprogramming abstraction
• Specifies metaprogram code and dependencies
• Can annotate any declaration or blockstatement
• Allows easy reuse of metaprogrammingconstructs
• Here defined by user class named Property
Meta-Annotations
@@Property private int x;
• Declarative metaprogramming abstraction
• Specifies metaprogram code and dependencies
• Can annotate any declaration or blockstatement
• Allows easy reuse of metaprogrammingconstructs
• Here defined by user class named Property
Meta-Annotations
@@Property private int x;
• Declarative metaprogramming abstraction
• Specifies metaprogram code and dependencies
• Can annotate any declaration or blockstatement
• Allows easy reuse of metaprogrammingconstructs
• Here defined by user class named Property
Meta-Annotation Dependencies@@GenerateConstructorFromProperties
public class Location {
@@Property private int x;
@@Property private int y;
public String toString() {
return "("+this.x+","+this.y+")";
}
}
• Meta-annotation defns. include dependencies• @@Property is a member of target “property”• @@GenerateConstructorFromProperties
depends on “property”
Meta-Annotation Dependencies@@GenerateConstructorFromProperties
public class Location {
@@Property private int x;
@@Property private int y;
public String toString() {
return "("+this.x+","+this.y+")";
}
}
• Meta-annotation defns. include dependencies
• @@Property is a member of target “property”• @@GenerateConstructorFromProperties
depends on “property”
Meta-Annotation Dependencies@@GenerateConstructorFromProperties
public class Location {
@@Property private int x;
@@Property private int y;
public String toString() {
return "("+this.x+","+this.y+")";
}
}
• Meta-annotation defns. include dependencies• @@Property is a member of target “property”
• @@GenerateConstructorFromProperties
depends on “property”
Meta-Annotation Dependencies@@GenerateConstructorFromProperties
public class Location {
@@Property private int x;
@@Property private int y;
public String toString() {
return "("+this.x+","+this.y+")";
}
}
• Meta-annotation defns. include dependencies• @@Property is a member of target “property”• @@GenerateConstructorFromProperties
depends on “property”
BSJ Dependency Graph
@@Property @@Property
@@GenerateConstructorFromProperties
φ1
φ3
φ2
property
• One node per metaprogram
• @@Property participates in “property” target
• @@GenerateConstructorFromProperties
depends on “property”
BSJ Dependency Graph
@@Property @@Property
@@GenerateConstructorFromProperties
φ1
φ3
φ2
property
• One node per metaprogram
• @@Property participates in “property” target
• @@GenerateConstructorFromProperties
depends on “property”
BSJ Dependency Graph
@@Property @@Property
@@GenerateConstructorFromProperties
φ1
φ3
φ2
property
• One node per metaprogram
• @@Property participates in “property” target
• @@GenerateConstructorFromProperties
depends on “property”
BSJ Dependency Graph
@@Property @@Property
@@GenerateConstructorFromProperties
φ1
φ3
φ2
property
• One node per metaprogram
• @@Property participates in “property” target
• @@GenerateConstructorFromProperties
depends on “property”
BSJ Dependency Graph
@@Property @@Property
@@GenerateConstructorFromProperties
φ1
φ3
φ2
property
• One node per metaprogram
• @@Property participates in “property” target
• @@GenerateConstructorFromProperties
depends on “property”
BSJ Dependency Graph
@@Property @@Property
@@GenerateConstructorFromProperties
φ1
φ3
φ2
property
• One node per metaprogram
• @@Property participates in “property” target
• @@GenerateConstructorFromProperties
depends on “property”
BSJ Dependency Graph
@@Property @@Property
@@GenerateConstructorFromProperties
φ1
φ3
φ2
property
• One node per metaprogram
• @@Property participates in “property” target
• @@GenerateConstructorFromProperties
depends on “property”
BSJ Dependency Graph
@@Property @@Property
@@GenerateConstructorFromProperties
φ1
φ3
φ2
property
• φ3 depends on φ1
• φ3 depends on φ2
ρ
◦
◦
BSJ Dependency Graph
@@Property @@Property
@@GenerateConstructorFromProperties
φ1
φ3
φ2
property
• φ3 depends on φ1
• φ3 depends on φ2
ρ
◦
◦
BSJ Dependency Graph
@@Property @@Property
@@GenerateConstructorFromProperties
φ1
φ3
φ2
property
• φ3 depends on φ1
• φ3 depends on φ2
ρ
◦
◦
BSJ Dependency Graph
@@Property @@Property
@@GenerateConstructorFromProperties
φ1
φ3
φ2
property
• φ3 depends on φ1
• φ3 depends on φ2
ρ
◦
◦
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Execute φ1 obtaining δ̄1.
• Execute φ2 obtaining δ̄2.
• Prove Jδ̄1K and Jδ̄2K commute.
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Execute φ1 obtaining δ̄1.
• Execute φ2 obtaining δ̄2.
• Prove Jδ̄1K and Jδ̄2K commute.
Execution Example
ρ
δ̄1
φ1
+getX
+setX
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Execute φ1 obtaining δ̄1.
• Execute φ2 obtaining δ̄2.
• Prove Jδ̄1K and Jδ̄2K commute.
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Execute φ1 obtaining δ̄1.
• Execute φ2 obtaining δ̄2.
• Prove Jδ̄1K and Jδ̄2K commute.
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2 +getY
+setY
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Execute φ1 obtaining δ̄1.
• Execute φ2 obtaining δ̄2.
• Prove Jδ̄1K and Jδ̄2K commute.
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Execute φ1 obtaining δ̄1.
• Execute φ2 obtaining δ̄2.
• Prove Jδ̄1K and Jδ̄2K commute.
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Execute φ1 obtaining δ̄1.
• Execute φ2 obtaining δ̄2.
• Prove Jδ̄1K and Jδ̄2K commute.
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Execute φ1 obtaining δ̄1.
• Execute φ2 obtaining δ̄2.
• Prove Jδ̄1K and Jδ̄2K commute.
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Execute φ1 obtaining δ̄1.
• Execute φ2 obtaining δ̄2.
• Prove Jδ̄1K and Jδ̄2K commute.
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Apply Jδ̄1K and Jδ̄2K to ρ.
• Execute φ3 on the result to get δ̄3.
• Apply Jδ̄3K to get the final object program.
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Apply Jδ̄1K and Jδ̄2K to ρ.
• Execute φ3 on the result to get δ̄3.
• Apply Jδ̄3K to get the final object program.
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Apply Jδ̄1K and Jδ̄2K to ρ.
• Execute φ3 on the result to get δ̄3.
• Apply Jδ̄3K to get the final object program.
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Apply Jδ̄1K and Jδ̄2K to ρ.
• Execute φ3 on the result to get δ̄3.
• Apply Jδ̄3K to get the final object program.
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Apply Jδ̄1K and Jδ̄2K to ρ.
• Execute φ3 on the result to get δ̄3.
• Apply Jδ̄3K to get the final object program.
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Apply Jδ̄1K and Jδ̄2K to ρ.
• Execute φ3 on the result to get δ̄3.
• Apply Jδ̄3K to get the final object program.
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Apply Jδ̄1K and Jδ̄2K to ρ.
• Execute φ3 on the result to get δ̄3.
• Apply Jδ̄3K to get the final object program.
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Apply Jδ̄1K and Jδ̄2K to ρ.
• Execute φ3 on the result to get δ̄3.
• Apply Jδ̄3K to get the final object program.
Execution Example
ρ
δ̄1
φ1
δ̄2
φ2
+getX
+setX
+getY
+setY
+getY
+setY
+getX
+setX
∼=
Jδ̄1K Jδ̄2K
Jδ̄2K Jδ̄1K
◦
δ̄3
φ3
ρ′
Jδ̄3K
• Apply Jδ̄1K and Jδ̄2K to ρ.
• Execute φ3 on the result to get δ̄3.
• Apply Jδ̄3K to get the final object program.
Difference-Based MetaprogrammingSummary
• Ambiguities detected at compile-time
• Metaprograms can inspect their environments
• Modular, declarative metaprogramming style
• Suitable for OO languages like Java
Difference-Based MetaprogrammingSummary
• Ambiguities detected at compile-time
• Metaprograms can inspect their environments
• Modular, declarative metaprogramming style
• Suitable for OO languages like Java
Difference-Based MetaprogrammingSummary
• Ambiguities detected at compile-time
• Metaprograms can inspect their environments
• Modular, declarative metaprogramming style
• Suitable for OO languages like Java
Difference-Based MetaprogrammingSummary
• Ambiguities detected at compile-time
• Metaprograms can inspect their environments
• Modular, declarative metaprogramming style
• Suitable for OO languages like Java
Backstage Java Implementation
• Working reference implementation available
• Includes source (∼50k SLOC)
• Full superset of Java 1.6
Backstage Java Implementation
• Working reference implementation available
• Includes source (∼50k SLOC)
• Full superset of Java 1.6
Backstage Java Implementation
• Working reference implementation available
• Includes source (∼50k SLOC)
• Full superset of Java 1.6
BSJ Standard Library – @@Memoized
@@Memoized
• Class for generating images
• Each image is generated from pair of Colors
• Memoizing image generation routine forperformance
• Store cached images in a private Map keyed byinput to generation method
BSJ Standard Library – @@Memoized
@@Memoized
• Class for generating images
• Each image is generated from pair of Colors
• Memoizing image generation routine forperformance
• Store cached images in a private Map keyed byinput to generation method
BSJ Standard Library – @@Memoized
@@Memoized
• Class for generating images
• Each image is generated from pair of Colors
• Memoizing image generation routine forperformance
• Store cached images in a private Map keyed byinput to generation method
BSJ Standard Library – @@Memoized
@@Memoized
• Class for generating images
• Each image is generated from pair of Colors
• Memoizing image generation routine forperformance
• Store cached images in a private Map keyed byinput to generation method
BSJ Standard Library – @@Memoized
@@Memoized
• Class for generating images
• Each image is generated from pair of Colors
• Memoizing image generation routine forperformance
• Store cached images in a private Map keyed byinput to generation method
BSJ Standard Library – @@Memoized
public class ImageGenerator {
@@Memoized
public Image gen(Color a, Color b) {· · · }}
BSJ Standard Library – @@Memoized
public class ImageGenerator {
@@Memoized
public Image gen(Color a, Color b) {· · · }}
BSJ Standard Library – @@Memoized
public class ImageGenerator {
private static class Key {
private Color a;
private Color b;
· · ·}
public Image gen(Color a, Color b) {· · · }
public Image gen(Color a, Color b) {
/* return cache value, igen as needed */
}
}
BSJ Standard Library – @@Memoized
public class ImageGenerator {
private static class Key {
private Color a;
private Color b;
· · ·}
private Map<???,Image> cache = new · · ·public Image gen(Color a, Color b) {· · · }
public Image gen(Color a, Color b) {
/* return cache value, igen as needed */
}
}
BSJ Standard Library – @@Memoized
public class ImageGenerator {
private static class Key {
private Color a;
private Color b;
· · ·}
private Map<???,Image> cache = new · · ·public Image gen(Color a, Color b) {· · · }
public Image gen(Color a, Color b) {
/* return cache value, igen as needed */
}
}
BSJ Standard Library – @@Memoized
public class ImageGenerator {
private static class Key {
private Color a;
private Color b;
· · ·}
private Map<Key,Image> cache = new · · ·public Image gen(Color a, Color b) {· · · }
public Image gen(Color a, Color b) {
/* return cache value, igen as needed */
}
}
BSJ Standard Library – @@Memoized
public class ImageGenerator {
private static class Key {
private Color a;
private Color b;
· · ·}
private Map<Key,Image> cache = new · · ·private Image igen(Color a, Color b) {· · · }
public Image gen(Color a, Color b) {
/* return cache value, igen as needed */
}
}
BSJ Standard Library – @@Memoized
public class ImageGenerator {
private static class Key {
private Color a;
private Color b;
· · ·}
private Map<Key,Image> cache = new · · ·private Image igen(Color a, Color b) {· · · }public Image gen(Color a, Color b) {
/* return cache value, igen as needed */
}
}
BSJ Standard Library – @@Memoized
public class ImageGenerator {
@@Memoized
public Image gen(Color a, Color b) {· · · }}
Expressiveness
Difference-based metaprogramming separatesanalysis from modification.
public class Example {
private int x = 0;
private int y = 0;
@@LogAndCount
public void foo() { · · · }
@@LogAndCount
public void bar() { · · · }
}