Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Recaf: Java Dialects as Libraries

Recaf: Java Dialects as Libraries

Recaffeinating Java ☕️ with custom semantics and extensions

http://www.recaf.org

Aggelos Biboudis

October 31, 2016
Tweet

More Decks by Aggelos Biboudis

Other Decks in Research

Transcript

  1. 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
  2. ‘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
  3. 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)
  4. How can we alter Java’s syntax and semantics without either

    altering the stock compiler or programming in language workbenches?
  5. 6 ― Harold Abelson, 
 Structure and Interpretation of Computer

    Programs “Programs must be written for people to read, and only incidentally for machines to execute.”
  6. 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
  7. 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)))
  8. Usage • Experimentation with Java semantics • Domain Specific Language

    creation • Embedding libraries • AOP • Generating code • … 9 using just Java }
  9. What the programmer writes recaf Using<String> alg = new Using<String>()

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

    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
  11. Definition of Using interface Using<R> extends FullJavaDirect<R> { default <U

    extends Closeable> IExec Using(ISupply<U> r, Function<U, IExec> 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
  12. Virtualizing Statements • Step 1: transforming 
 the source program

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

    mechanical /w fixed set of rules • transparent • written in Rascal 14 powered by:
  14. 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, S> { R Method(S s); } interface MuJava<R, S> { S Exp(Supplier<Void> e); S If(Supplier<Boolean> c, S s1, S s2); <T> S For(Supplier<Iterable<T>> e, Function<T, S> s); <T> S Decl(Supplier<T> e, Function<T, S> s); S Seq(S s1, S s2); S Return(Supplier<R> e); S Empty(); } 15
  15. Two Kinds of Definitions • direct style (our Using example

    from earlier) interface MuJavaBase<R> extends MuJava<R, IExec> { ... } 
 interface IExec { void exec(); } essentially interpretation 16
  16. Two Kinds of Definitions • continuation passing style when we

    also want to alter the control flow interface MuJavaCPS<R> extends MuJava<R, SD<R>> { ... } 
 interface SD<R> { void accept(K<R> 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
  17. Example: Backtracking List<Pair> solve(recaf Backtrack<Pair> 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 *
  18. Example: Backtracking interface Backtrack<R>
 extends MuJavaCPS<R>, MuJavaMethod<List<R>, SD<R>> { default

    List<R> Method(SD<R> body) {
 List<R> result = new ArrayList<>();
 body.accept(ret " { result.add(ret); }, () " {}); return result; } default <T> SD<R> Choose(Supplier<Iterable<T>> e, Function<T, SD<R>> s) { return (r, s0) " {
 for (T t: e.get()) s.apply(t).accept(r, s0); }; } 19
  19. 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:
  20. Case Study 1:
 Spicing up Java with Side-Effects 22 recaf

    Iterable<Integer> range(int s, int n) { if (n > 0) { yield! s; yieldFrom! range(s + 1, n - 1); } } recaf Future<Integer> task(String url) await String html = fetchAsync(url); return html.length(); } recaf <X> Observable<X> print(Observable<X> src) { awaitFor (X x: src) { System.out.println(x); yield! x; } }
  21. Case Study 2:
 Parsing Expression Grammars (PEGs) 24 recaf Parser<Exp>

    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
  22. 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
  23. 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
  24. 27

  25. Let’s have a chat at the poster session Tijs van

    der Storm Aggelos Biboudis Pablo Inostroza 28 www.recaf.org