jUCM: Universal Class Morphing

jUCM: Universal Class Morphing

This is the slide deck of my talk at MASPEGHI15 about extending the meta-programming technique of class morphing.

Paper: http://arxiv.org/abs/1506.05270
Workshop: http://2015.ecoop.org/track/MASPEGHI-2015-papers

B81db221127979fbf254c4ffba7ba286?s=128

Aggelos Biboudis

July 05, 2015
Tweet

Transcript

  1. jUCM: Universal Class Morphing (position paper) MechAnisms for SPEcialization, Generalization

    and inheritance (MASPEGHI 2015) Aggelos Biboudis, George Fourtounis and Yannis Smaragdakis @biboudis, @gf0ur University of Athens 5 July 2015
  2. Overview 1. Present a meta-programming technique called class morphing. •

    Dissect the syntax through an example • A casual discussion about the type system 2. Introducing Universal Class Morphing • A walk through the idea via examples, examples, examples 3. Research challenges University of Athens 2 5/7/2015
  3. Program Generation Concepts • how we generate/transform programs today? 

    source-code-as-text manipulation  macros  staging  AOP  bytecode engineering 5/7/2015 University of Athens 3
  4. Class Morphing statically safe, modular, meta-programming statically safe: the meta-program

    is checked for errors at compile time. modular: the meta-program is parameterized. Will it work for any class? meta-programming: generate class declarations University of Athens 4 5/7/2015
  5. Morphed class (morphJ language) class Logging<class X> extends X {

    <R, Y*>[meth] for (R meth (Y) : X.methods) R meth (Y a) { R r = super.meth(a); print("Returned: " + r); return r; } } University of Athens 5 5/7/2015 generate methods with this body
  6. Usage example class Customer { Order orderItemsInCart (Cart cart) {}

    Order orderItems (List<Items> items) {} String getName () {} } … Customer c = new Logging<Customer>(); University of Athens 6 5/7/2015
  7. Essentially this declaration class Logging<Customer> extends Customer { public Order

    orderItemsInCart (Cart cart) { Order r = super.meth(cart); print("Returned: " + r); return r; } public Order orderItems (List<Items> items) { Order r = super.meth(items); print("Returned: " + r); return r; } } generated University of Athens 7 5/7/2015
  8. Type checking challenges • Identify cases where 2 or more

    reflective declaration may produce conflicting declarations • Identify references to members that may exist reflectively University of Athens 8 5/7/2015
  9. Validity of references class LogIntArg<class Y> { Logging<Y> loggedY; <T>[n]

    for (T n(int) : Y.methods) T n (int s) { print (“number arg: " + s); return loggedY.n(s); } } class Logging<class X> extends X { <R, Y*>[meth] for (R meth (Y) : X.methods) R meth (Y a) { … } } will this method lookup succeed? <T>[n] for (T n(int) : Y.methods) <R, Y*>[meth] for (R meth (Y) : X.methods) University of Athens 9 5/7/2015
  10. Validity of references only if meth range more general than

    n range (meth ⊆ n) University of Athens 10 5/7/2015 <T>[n] for (T n(int) : Y.methods) <R, Y*>[meth] for (R meth (Y) : X.methods)
  11. What we saw until now • “Writing programs that morph

    over programs” • Syntax • A glimpse of the type system and how it is modular • A taste of the use cases University of Athens 11 5/7/2015
  12. The idea behind Universal Class Morphing • Why pattern over

    methods/fields only? • Introducing pattern-matching over types. E.g., • for all classes of a module, create new classes that morph over the original ones • for all supertypes of a class, create new ones that… • for all nested classes of a class that support a certain interface, create subclasses that… • (mixin layers++) • for all classes in a set, add a new supertype to them • All with modular type safety! University of Athens 12 5/7/2015
  13. Universal Class Morphing • morphJ used patterns over methods (and

    fields) <T>[n] for (public T n(String) : Y.methods ) public T n (String s) • jUCM aims to introduce patterns over classes <C, S> for (C extends S : L.classes) static class C { … } University of Athens 13 5/7/2015
  14. Example 1 • How to maintain a delegation-based view of

    a hierarchy? class Library { static class Vector { boolean isEmpty() {} } static class Stack extends Vector { } } class Library { static class Vector { boolean isEmpty() {} } static class Stack { Vector subobject; boolean isEmpty() { subobject.isEmpty(); } } } we have this we want to generate this University of Athens 14 5/7/2015
  15. Example 1 • How to maintain a delegation-based view of

    a hierarchy? class Delegate<class L> { <C, S> for (C extends S : L.classes) static class C { S subobject#S; <R, A*> [m] for(public R m(A) : S.methods) R m(A a) { return subobject#S.m(a); } } } for all classes in any L introduce a class with the same name delegate calls University of Athens 15 5/7/2015 /w a sub field
  16. Example 2 interface Alert { void alert(); } class AlertingGraph

    <class X> { [N] for (N : X.classes) static class N extends X.N implements Alert { [m] for(public void m () : X.N.methods) public void m() { alert(); super.m(); } void alert() { print("Alerted!"); } } } introduce a new interface for all classes in any class X make all classes implement this interface call alert in all void methods University of Athens 16 5/7/2015
  17. Example 3 • A company hierarchy (taken from Lämmel et

    al., SYB paper) data Company = C [Dept] data Dept = D Name Manager [SubUnit] data SubUnit = PU Employee | DU Dept data Employee = E Person Salary data Person = P Name Address data Salary = S Float type Manager = Employee type Name = String type Address = String University of Athens 17 5/7/2015
  18. Example 3 • Corresponds to a hierarchy based on subtyping

    class Hierarchy { abstract class Company {} static class C extends Company { List<Dept> departments; } abstract class Dept {} static class D extends Dept { String name; Employee manager; List<SubUnit> subUnits; } abstract class SubUnit {} static class PU extends SubUnit { Employee employee; } static class DU extends SubUnit { Dept department; } abstract class Employee {} static class E extends Employee { Person person; Salary salary; } abstract class Person {} static class P extends Person { Name name; Address address; } abstract class Salary {} static class S extends Salary { Float data; } } University of Athens 18 5/7/2015
  19. Example 3 • Which is made visitable with boilerplate code

    • An interface CompanyVisitor that contains all visit* variants • The same classes implementing the corresponding interface + the appropriate accept methods. class Hierarchy { abstract class Company {} static class C extends Company { List<Dept> departments; } abstract class Dept {} static class D extends Dept { String name; Employee manager; List<SubUnit> subUnits; } abstract class SubUnit {} static class PU extends SubUnit { Employee employee; } static class DU extends SubUnit { Dept department; } abstract class Employee {} static class E extends Employee { Person person; Salary salary; } abstract class Person {} static class P extends Person { Name name; Address address; } abstract class Salary {} static class S extends Salary { Float data; } } interface CompanyElement { <R> void accept(CompanyVisitor<R> visitor); } interface CompanyVisitor<R> { R visitC(C c); R visitD(D d); R visitPU(PU pu); R visitDU(DU du); R visitE(E e); R visitP(P p); R visitS(S s); } abstract static class Company implements CompanyElement { } static class C extends Company { List<Dept> departments; public <R> void accept(CompanyVisitor<R> visitor) { visitor.visitC(this); } } abstract static class Dept implements CompanyElement { } static class D extends Dept { String name; Employee manager; List<SubUnit> subUnits; public <R> void accept(CompanyVisitor<R> visitor) { visitor.visitD(this); } } abstract static class SubUnit implements CompanyElement { } static class PU extends SubUnit { Employee employee; public <R> void accept(CompanyVisitor<R> visitor) { visitor.visitPU(this); } } static class DU extends SubUnit { Dept department; public <R> void accept(CompanyVisitor<R> visitor) { visitor.visitDU(this); } } abstract static class Employee implements CompanyElement { } static class E extends Employee { Person person; Salary salary; public <R> void accept(CompanyVisitor<R> visitor) { visitor.visitE(this); } } abstract static class Person implements CompanyElement { } static class P extends Person { Name name; Address address; public <R> void accept(CompanyVisitor<R> visitor) { visitor.visitP(this); } } abstract static class Salary implements CompanyElement { } static class S extends Salary { float data; public <R> void accept(CompanyVisitor<R> visitor) { visitor.visitS(this); } } clean hierarchy with traversable code University of Athens 19 5/7/2015
  20. Example 3 • Boilerplate can be scraped with 2 morphed

    definitions class VisitableHierarchy { [N] for(abstract static N : Hierarchy.classes) abstract static class N implements CompanyElement { } <T> [N] for(static N extends T : Hierarchy.classes) static class N extends Hierarchy.N { public <R> void accept(CompanyVisitor<R> visitor){ visitor.visit#E(this); } } } interface CompanyVisitor<R> { <M extends Object> [C] for (C extends M : Hierarchy.classes) R visit#C(C e); } 1) 2) University of Athens 20 5/7/2015
  21. Research challenges • How modularity is going to be preserved?

    • Will type checking stay sound? • Are the semantics of morphJ really pluggable with jUCM? • Separate compilation? • Worth exploring related work: • F# static generics • TASTY-like format introduced for serialization of typed information for metaclasses. University of Athens 21 5/7/2015
  22. Thank you • This deck: https://speakerdeck.com/biboudis/jucm- universal-class-morphing • Our MASPEGHI15

    position paper: http://arxiv.org/abs/1506.05270 • Original paper for Morphing: Structurally shaping a class by reflecting on others University of Athens 22 5/7/2015
  23. 5/7/2015 University of Athens 23

  24. Type checking key concepts • Key concepts • Reason about

    generation ranges of declarations or references • Set-theoretic reasoning • Disjoint ranges mean non-conflicting declarations • Containing ranges mean that a reference is valid University of Athens 24 5/7/2015
  25. Disjoint declarations • Generation ranges are checked if they unify

    class DisjointDecs<class X> { <R>[m] for(R m (int) : X.methods) R m (int i) { ... } <S> [n] for(S n (int) : X.methods) S n (int i, String s) { ... } } University of Athens 25 5/7/2015
  26. Disjoint declarations • If they still unify, then reflective patterns

    are employed to check the reflection conditions for exclusivity class StillUnique<class X> { <A1>[m]for(String m (A1) : X.methods) void m (A1 a) { ... } <A2>[n]for(int n (A2) : X.methods) void n (A2 a) { ... } } University of Athens 26 5/7/2015