310 likes | 410 Views
Flattening versus Direct semantics for Featherweight Jigsaw Giovanni Lagorio , Marco Servetto and Elena Zucca. Plan of the talk. Flattening and Direct semantics By example: Inheritance Featherweight Jigsaw ( FJig ) (nice and clean) surface syntax Generalized inheritance
E N D
Flattening versus Direct semantics for Featherweight JigsawGiovanni Lagorio, Marco Servetto and Elena Zucca
Plan of the talk • Flattening and Direct semantics • By example: Inheritance • Featherweight Jigsaw (FJig) • (nice and clean) surface syntax • Generalized inheritance • I’ll gloss over its (ugly but equivalent) core syntax • Conclusions
The intuition of Inheritance • Please think how you’d explain inheritance • to a muggle1(1 here, indicates someone who’s never heard of OO) • Odds are you’re thinking of flattening semantics
Flattening Semantics of inheritance class C1 { void m1() {…} } What does this mean? class C2 extends C1 { void m2() {…} } class C2 { void m1() {…} void m2() {…} } It’s as we wrote C2 like this
The general idea • Giving semantics of some feature by translating it away • Programs translated in (equivalent) programs that don’t use the feature class C2 { void m1() {…} void m2() {…} } • Extension flattened into the vanilla language Language • Let’s see pros and cons class C2 extends C1 { void m2() {…} } ExtendedLanguage
Pros: it’s intuitive class C1 { void m1() {…} } class C2 { void m1() {…} void m2() {…} } class C1 { void m1() {…} } class C2 extends C1 { void m2() {…} } class C3 extends C2 { void m3() {…} } class C3 { void m1() {…} void m2() {…} void m3() {…} }
Pros: good old method lookup class C1 { void m1() {…} } class C2 { void m1() {…} void m2() {…} } class C3 { void m1() {…} void m2() {…} void m3() {…} } • Lookup as easy as it can get • No changes in the definition (the program changes, not lookup) • For instance,lookup(C2, …)=(inheritance has been flattened out)
Cons: compiling dependencies class C1 { void m1() {…} } class C2 { void m1() {…} void m2() {…} } class C3 { void m1() {…} void m2() {…} void m3() {…} } class C1 { void m1() {…} } class C2 extends C1 { void m2() {…} } class C3 extends C2 { void m3() {…} } the binarydepends on
Flattening Semantics, recap • Intuitive:good tool for teaching/understanding • Been used to give the semantics of mixins, traits, … but • Poor implementation choice • Lot of compiling dependencies (unlike Java, like C++) • Code bloating
The implementation of Inheritance • Please think how you’d implement inheritance • Odds are you’re thinking of direct semantics
The idea • Classes can be defined in new ways • Since programs are not translated,good old method lookup can’t work anymore class C1 { void m1() {…} } Language lookup(C2, m1)=??? We can compute lookup(C, m)=… For instance, lookup(C1, m1)=… class C2 extends C1 { void m2() {…} } ExtendedLanguage
Extended method lookup class C1 { void m1() {…} } class C2 extends C1 { void m2() {…} } class C3 extends C2 { void m3() {…} } • Needs to know what extends means • For instance, lookup(C3, m2) starts from C3 • Don’t find m2, so proceeds with C2 • And finds m2
Flexible class definitions • class C ClassExpression • ClassExpression::=BasicClass | mergeClassExpression1, ClassExpression2 | rename N to N’ inClassExpression | hide N inClassExpression | …others…BasicClass ::= { …constr/fields/methods…}
Basic class declaration • One constructor; takes any kind of parameters • Internal representation hidden from clients • A series of members: fields and methods • Members can be: • abstract • virtual • frozen • local no definition “someone” is expected to provide it there is a definition,but it can be later replaced there is a definition, that current clients will see forever (even if replaced) there is a definition, that no other object will ever see
FJig • Nice per se • More than that, can encode: • standard inheritance • mixins • traits • … it’s a general framework for sw composition • Wouldn’t be wonderful to have • an intuitive (flattening) semantics and • a (rather complex but) efficient (direct) one? • Actually, no it wouldn’t • … unless they’re equivalent! And they are!
An example • I’m “cheating” using • an extra-sugared syntax • primitive types and void • class A {abstractvoid m();frozen intanswer() { return41; }local intloc() { return1; }} • class B {frozen int answer() { return42; }virtual void m() { loc(); } local intloc() { returnanswer(); } } • class C merge (rename answer towrongAnswerin A),B • …what’s new C().answer()?
Flattening steps (1 of 5) • class C merge (rename answer towrongAnswerin A), B • class C merge (rename answer towrongAnswerin{abstractvoid m();frozen intanswer() { return41; }local intloc() { return1; } } ), B
Flattening steps (2 of 5) • classC merge (rename answer towrongAnswerin{abstractvoid m();frozen intanswer() { return41; }local intloc() { return1; } } ), B • class C merge{abstractvoid m();frozen intwrongAnswer() { return41; }local intloc() { return1; }} , B
Flattening steps (3 of 5) • class C merge{abstractvoid m();frozen intwrongAnswer() { return41; }local intloc() { return1; } } , {frozen intanswer() { return42; }virtual void m() { loc(); }local intloc() { returnanswer(); } } • classC merge{abstractvoid m();frozen intwrongAnswer() { return41; }local intloc() { return1; }} , B
Flattening steps (4 of 5) • class C merge{abstractvoid m();frozen intwrongAnswer() { return41; }local intloc() { return1; } } , {frozen intanswer() { return42; }virtual void m() { loc’(); }local intloc’() { returnanswer(); } }
Flattening steps (5 of 5) • class C { // equivalent flattened definitionfrozen intwrongAnswer() { return41; }local intloc() { return1; }frozen intanswer() { return42; }virtual void m() { loc’(); }local intloc’() { returnanswer(); } } • now we can easily see what new C().answer() is • and, quite obviously , it’s 42
Direct Semantics class B {frozen intanswer() { return 42; }virtual void m() { loc(); } local intloc() { return answer(); } } class A {abstractvoid m();frozen intanswer() { return 41; }local intloc() { return1; }} class C merge (rename answer towrongAnswerin A),B • again, what does new C().answer() means? • what is lookup(C, answer)?
Direct Semantics class B {frozen intanswer() { return 42;}virtual void m() { loc(); } local intloc() { return answer(); } } class A {abstractvoid m();frozen intanswer() { return 41; }local intloc() { return1; }} class C merge (rename answer towrongAnswerin A), B lookup(C, answer) = lookup(merge …, answer) = = lookup((rename…), answer)and non-deterministically = lookup(B, answer)
Lookup on a rename expression lookup(renameFromNtoToNinClassExpression, N)= • failure if N=FromN • lookup(ClassExpression, FromN) if N=ToN • lookup(ClassExpression, N) otherwise In the example: lookup((rename answer towrongAnswerin A), answer) fails, so lookup(C, answer) = … 2 choices … = lookup(B, answer)
Lookup on a name lookup(B, answer) = lookup(ClassExpression, answer) where ClassExpressionis the class expression of B, which is a base (flatten) class. So, we can conclude. Believe it or not, I’ve just scratched the surface: direct semantics is no picnic
Conclusions and further work • Flatten semantics: easy, intuitive • but “performs” poorly • Direct semantics can be (rather) complex • but it’s a good choice for implementation • FJig: general language for software composition • encompasses inheritance, mixin, traits…. • Given both semantics and proved equivalent • Implemented interpreter as master-thesis:http://www.disi.unige.it/person/LagorioG/FJig/ • Exploring the equivalence for feature requiring static types (e.g. overloading and static binding) • Investigating smart implementation techniques