Slide 1

Slide 1 text

15th International Conference on Generative Programming: Concepts & Experience (GPCE16) Recaf Java Dialects as Libraries Amsterdam, 31/10/2016 Aggelos Biboudis Pablo Inostroza Tijs van der Storm

Slide 2

Slide 2 text

‘5.7.2 Coffee with adjusted caffeine content’ In order to reduce the physiological side effects of `health-deleterious non-caffeine components' in the beverage for heavy drinkers, coffee with an enhanced caffeine content (recaffeinated coffee) can be prepared by mixing roast and ground coffee with ground caffeine crystals or by spraying a liquid caffeine solution on to ground coffee. Coffee: Recent Developments by Ronald Clarke, O. G. Vitzthum, ISBN: 978-0-632-05553-1

Slide 3

Slide 3 text

Java is caffeinated ☕ with its fixed syntax and semantics Alas, programming styles are retrofitted instead of being pure and beautiful! (e.g., async, reactive, streams, coroutines, solvers, DSLs, declarative GUIs, etc)

Slide 4

Slide 4 text

Fixed syntax and semantics entail limited understandability and language extensions often need external tools

Slide 5

Slide 5 text

How can we alter Java’s syntax and semantics without either altering the stock compiler or programming in language workbenches?

Slide 6

Slide 6 text

6 ― Harold Abelson, 
 Structure and Interpretation of Computer Programs “Programs must be written for people to read, and only incidentally for machines to execute.”

Slide 7

Slide 7 text

What is Recaf? • an open source framework for Java Dialects creation (check www.recaf.org) • enables • syntactic extensions’ creation • semantics extensions and redefinitions using 
 object algebras • supports • two levels of extensibility: i) statements & ii) expressions • two kinds of definitions: i) direct & ii) CPS 7

Slide 8

Slide 8 text

What is Recaf? • Domain-Specific Language integration for Java • do-notation in Haskell • Computation Expressions in F# • scala-virtualized in Scala 8 do x1 <- fun1 x2 <- fun2 funnier x1 x2 compute { for x in 1..2 do return x } __match.runOrElse(x)(x1 => P.unapply(x1).flatMap(x2 => __match.one(x2._1 + x2._2)))

Slide 9

Slide 9 text

Usage • Experimentation with Java semantics • Domain Specific Language creation • Embedding libraries • AOP • Generating code • … 9 using just Java }

Slide 10

Slide 10 text

What the programmer writes recaf Using alg = new Using() {}; recaf String usingExample(String path) { using (Resource r : new Resource(path)) { return r.readLine(); } } using the new construct declaring the new semantics 10

Slide 11

Slide 11 text

What Recaf produces Using alg = new Using() { }; String usingExample(String path) {
 return (String) alg.Method(alg.Using( () -> new Resource(path), (Resource r) -> { return alg.Return(() -> r.readLine()); })); } code is transformed into calls to methods of the semantics object notice the signature of Using 11

Slide 12

Slide 12 text

Definition of Using interface Using extends FullJavaDirect { default IExec Using(ISupply r, Function b) { return _ -> { U u = null; try { u = r.get(); b.apply(u).exec(null); } finally { if (u != null) u.close(); } }; } } direct semantics for java provided 12

Slide 13

Slide 13 text

Virtualizing Statements • Step 1: transforming 
 the source program • mechanical /w fixed set of rules • transparent • written in Rascal 13 powered by:

Slide 14

Slide 14 text

Extending Statements • Step 1.5: transforming the source program • mechanical /w fixed set of rules • transparent • written in Rascal 14 powered by:

Slide 15

Slide 15 text

Defining Statements • Step 2: defining the semantics • implementing an interface • Recaf comes with a predefined set to extend or override in case of new • written in plain Java by the developer interface MuJavaMethod { R Method(S s); } interface MuJava { S Exp(Supplier e); S If(Supplier c, S s1, S s2); S For(Supplier> e, Function s); S Decl(Supplier e, Function s); S Seq(S s1, S s2); S Return(Supplier e); S Empty(); } 15

Slide 16

Slide 16 text

Two Kinds of Definitions • direct style (our Using example from earlier) interface MuJavaBase extends MuJava { ... } 
 interface IExec { void exec(); } essentially interpretation 16

Slide 17

Slide 17 text

Two Kinds of Definitions • continuation passing style when we also want to alter the control flow interface MuJavaCPS extends MuJava> { ... } 
 interface SD { void accept(K r, K0 s); } dealing with denotations An OCaml developer will see: val SD : (r → unit) → (unit → unit) → unit A language designer will see: SD[[ · ]]ρ, σ , etc 17

Slide 18

Slide 18 text

Example: Backtracking List solve(recaf Backtrack alg) { choose Integer x = asList(1, 2, 3);
 choose Integer y = asList(4, 5, 6);
 if (x + y == 8) { return new Pair(x, y); } } 18 * replacing failure with a list of successes *

Slide 19

Slide 19 text

Example: Backtracking interface Backtrack
 extends MuJavaCPS, MuJavaMethod, SD> { default List Method(SD body) {
 List result = new ArrayList<>();
 body.accept(ret " { result.add(ret); }, () " {}); return result; } default SD Choose(Supplier> e, Function> s) { return (r, s0) " {
 for (T t: e.get()) s.apply(t).accept(r, s0); }; } 19

Slide 20

Slide 20 text

Virtualizing Expressions • the set of rules is extended, now including elements of expressions (literals, variables, this, method invocation, new, lambdas, etc) • e.g., for (Integer x: y) println(x + 1); // HOAS a.For(a.Var("y", y), Integer x " a.Exp( a.Invoke(a.This(this), "println", a.Add(a.Var("x", x), a.Lit(1))))); 20 powered by:

Slide 21

Slide 21 text

Case Study 1:
 Spicing up Java with Side-Effects 21

Slide 22

Slide 22 text

Case Study 1:
 Spicing up Java with Side-Effects 22 recaf Iterable range(int s, int n) { if (n > 0) { yield! s; yieldFrom! range(s + 1, n - 1); } } recaf Future task(String url) await String html = fetchAsync(url); return html.length(); } recaf Observable print(Observable src) { awaitFor (X x: src) { System.out.println(x); yield! x; } }

Slide 23

Slide 23 text

Case Study 2:
 Parsing Expression Grammars (PEGs) 23

Slide 24

Slide 24 text

Case Study 2:
 Parsing Expression Grammars (PEGs) 24 recaf Parser primary() { choice { alt "value": regexp String n = "[0-9]+"; return new Int(n); alt "bracket": lit! "("; let Exp e = addSub(); lit! ")"; return e; } } switch like declaration like declaration like return like

Slide 25

Slide 25 text

Discussion • Recaf is a lightweight tool that intercepts the compilation pipeline • Runtime performance depends on the implementation of the semantics • Interpretation is slow at the moment • For generative scenarios that cost is amortized 25

Slide 26

Slide 26 text

Future Work • Research … • Investigate compositionality (e.g., effect handlers, freer?) • Performance Assessment: Recaf, Partially Evaluated • Use Recaf to create a template language for JS / transpilation (with the syntax of Java, e.g., ASP.NET’s Razor) • Improve typing features toward modular type checking • class definitions - memory layout overriding • … and Development • Develop an ecosystem (e.g., a package manager for dialects, 
 e.g., recaf-pm install z3-extension async-extension) 26

Slide 27

Slide 27 text

27

Slide 28

Slide 28 text

Let’s have a chat at the poster session Tijs van der Storm Aggelos Biboudis Pablo Inostroza 28 www.recaf.org