Mixins and Traits

Mixins and Traits

◦ ◦◦◦ TECHNISCHE UNIVERSITAT¨ MUNCHEN¨ ◦◦◦◦ ◦ ◦ ◦◦◦ ◦◦◦◦ ¨ ¨ ◦ ◦◦ FAKULTAT FUR INFORMATIK Programming Languages Mixins and Traits Dr. Michael Petter Winter 2016/17 What advanced techiques are there besides multiple implementation inheritance? Outline Design Problems Cons of Implementation Inheritance 1 Inheritance vs Aggregation 1 2 (De-)Composition Problems Lack of finegrained Control 2 Inappropriate Hierarchies Inheritance in Detail A Focus on Traits 1 A Model for single inheritance 1 2 Inheritance Calculus with Separation of Composition and Inheritance Expressions Modeling 2 3 Modeling Mixins Trait Calculus Mixins in Languages Traits in Languages 1 (Virtual) Extension Methods 1 Simulating Mixins 2 Squeak 2 Native Mixins Reusability ≡ Inheritance? Codesharing in Object Oriented Systems is often inheritance-centric. Inheritance itself comes in different flavours: I single inheritance I multiple inheritance All flavours of inheritance tackle problems of decomposition and composition The Adventure Game Door ShortDoor LockedDoor canPass(Person p) canOpen(Person p) ? ShortLockedDoor canOpen(Person p) canPass(Person p) The Adventure Game Door <interface>Doorlike canPass(Person p) canOpen(Person p) Short canPass(Person p) Locked canOpen(Person p) ShortLockedDoor ! Aggregation & S.-Inheritance Door must explicitely provide canOpen(Person p) chaining canPass(Person p) Doorlike must anticipate wrappers ) Multiple Inheritance X The Wrapper FileStream SocketStream read() read() write() write() ? SynchRW acquireLock() releaseLock() ! Inappropriate Hierarchies Cannot inherit from both in turn with Multiple Inheritance (Many-to-One instead of One-to-Many Relation) Creating individual special wrapping Classes duplicates acquire/release code The Wrapper – Aggregation Solution Stream read() write() FileStream SocketStream read() read() write() write() SynchRW read() ! Aggregation write() acquireLock() Undoes specialization releaseLock() Needs common ancestor The Wrapper – Multiple Inheritance Solution FileStream SynchRW SocketStream read() acquireLock() read() write() releaseLock() write() SynchedFileStream SynchedSocketStream read() read() write() write() ! Duplication With multiple inheritance, read/write Code is essentially identical but duplicated for each particular wrapper Fragility SynchRW acquireLock() releaseLock() FileStream SocketStream read() read() write() write() SynchedFileStream SynchedSocketStream ! Inappropriate Hierarchies Implemented methods (acquireLock/releaseLock) to high (De-)Composition Problems All the problems of Duplication Fragility Lack of fine-grained control are centered around the question “How do I distribute functionality over a hierarchy” functional (de-)composition Classes and Methods The building blocks for classes are a countable set of method names N a countable set of method bodies B Classes map names to elements from the flat lattice B (called bindings), consisting of: > attribute offsets 2 N+ method bodies 2 or classes 2 C B n n m m c c ? abstract 1 2 1 ::: 2 1 2 > in conflict and the partial order ? v b v > for each b 2 B ? Definition (Abstract Class 2 C) A function c : N 7! B with at least one abstract image is called abstract class. Definition (Interface and Class) An abstract class c is called (with pre beeing the preimage) interface iff 8n2pre(c) : c(n) = ?. (concrete) class iff 8n2pre(c) : ? @ c(n) @ >. Computing with Classes and Methods Definition (Family of classes C) We call the set of all maps from names to bindings the family of abstract classes C := N 7! B. Several possibilites for composing maps C C: the symmetric join t, defined componentwise: 8 >b2 if b1 = ? or n2 = pre(c1) > <b1 if b2 = ? or n2 = pre(c2) (c1 t c2)(n) = b1 t b2 = where bi = ci(n) >b2 if b1 = b2 > :> otherwise in contrast, the asymmetric join t, defined componentwise: ( c1(n) if n 2 pre(c1) (c1 t c2)(n) = c2(n) otherwise Example: Smalltalk-Inheritance Smalltalk inheritance childrens methods dominate parents methods is the archetype for inheritance in mainstream languages like Java or C# inheriting smalltalk-style establishes a reference to the parent Definition (Smalltalk inheritance (.)) Smalltalk inheritance is the binary operator . : C × C 7! C, definied by c1 . c2 = fsuper 7! c2g t (c1 t c2) Example: Doors Door = fcanP ass 7! ?; canOpen 7! ?g LockedDoor = fcanOpen 7! 0x4204711g . Door = fsuper 7! Doorg t (fcanOpen 7! 0x4204711g t Door) = fsuper 7! Door; canOpen 7! 0x4204711; canP ass 7! ?g Excursion: Beta-Inheritance In Beta-style inheritance the design goal is to provide security wrt. replacement of a method by a different method. methods in parents dominate methods in subclass the keyword inner explicitely delegates control to the subclass Definition (Beta inheritance (/)) Beta inheritance is the binary operator / : C × C 7! C, definied by c1 / c2 = finner 7! c1g t (c2 t c1) Example (equivalent syntax): class Person{ String name= "Axel Simon"; public String toString(){ return name+inner.toString();}; }; class Graduate extends Person{ public extension String toString(){ return ", Ph.D.";}; }; Extension: Attributes Remark: Modelling attributes is not in our main focus. Anyway, most mainstream languages nowadays are designed so that attributes are not overwritten: Definition (Mainstream inheritance (.0)) The extended mainstream inheritance .0 : C × C 7! C binds attribute n statically and without overwriting: 8 >c2 if n = super > + 0 <> if n 2 pre(c1) ^ c2(n) 2 (N [ >) (c1 . c2)(n) = >c1(n) if n 2 pre(c1) > :c2(n) otherwise So what do we really want? Adventure Game with Code Duplication Door ShortDoor LockedDoor canPass(Person p) canOpen(Person p) ShortLockedDoor canOpen(Person p) canPass(Person p) Adventure Game with Mixins <mixin>Locked Door canOpen(Person p) canOpen(Person p) canPass(Person p) <mixin>Short mixin canPass(Person p) compose ShortLockedDoor Adventure Game with Mixins class Door{ boolean canOpen(Person p){ return true;}; boolean canPass(Person p){ returnp.size()< 210;}; } mixin Locked{ boolean canOpen(Person p){ if(!p.hasItem(key)) return false; else return super.canOpen(p); } } mixin Short{ boolean canPass(Person p){ if(p.height()>1) return false; else return super.canPass(p); } } class ShortDoor= Short(Door); class LockedDoor= Locked(Door); mixin ShortLocked= Short o Locked; class ShortLockedDoor= Short(Locked(Door)); class ShortLockedDoor2= ShortLocked(Door); Back to the blackboard! Abstract model for Mixins A Mixin is a unary second order type expression. In principle it is a curried version of the Smalltalk-style inheritance operator. In certain languages, programmers can create such mixin operators: Definition (Mixin) The mixin constructor mixin : C 7! (C 7! C) is a unary class function, creating a unary class operator, defined by: mixin(c) = λx : c . x ! Note: Mixins can also be composed ◦: Example: Doors Locked = fcanOpen 7! 0x1234g Short = fcanP ass 7! 0x4711g Composed = mixin(Short) ◦ (mixin(Locked)) = λx : Short . (Locked . x) = λx : fsuper 7! Lockedg t (fcanOpen 7! 0x1234; canP ass 7! 0x4711g . x) Wrapper with Mixins FileStream SocketStream read() read() write() write() mixin <mixin>SynchRW acquireLock() releaseLock() mixin SynchedFileStream SynchedSocketStream read() read() write() write() Mixins on Implementation Level Short class Door{ canPass() boolean canOpen(Person p)... boolean canPass(Person p)... super } mixin Locked{ Locked ... boolean canOpen(Person p)... } canOpen() mixin Short{ super boolean canPass(Person p)... } ... class ShortDoor Door = Short(Door); class ShortLockedDoor = Short(Locked(Door)); ... ! non-static super-References ShortDoor d dynamic dispatching without = new ShortLockedDoor(); precomputed virtual table Surely multiple inheritance is powerful enough to simulate mixins? Simulating Mixins in C++ template<class Super> class SyncRW: public Super { public: virtual int read(){ acquireLock(); int result= Super::read(); releaseLock(); return result; }; virtual void write(int n){ acquireLock(); Super::write(n); releaseLock(); }; // ... acquireLock & releaseLock }; Simulating Mixins in C++ template<class Super> class LogOpenClose: public Super { public: virtual void open(){ Super::open(); log("opened"); }; virtual void close(){ Super::close(); log("closed"); }; protected: virtual void log(char*s) { ... }; }; class MyDocument: public SyncRW<LogOpenClose<Document>> {}; True Mixins vs. C++ Mixins True Mixins super natively supported C++ Mixins Mixins as Template do not offer composite mixins Mixins reduced to templated superclasses C++ Type system not modular Can be seen as coding Mixins have to stay source pattern code Hassle-free simplified version of multiple inheritance Common properties of Mixins Linearization is necessary Exact sequence of Mixins is relevant Ok, ok, show me a language with native mixins! Ruby module Short def canPass(p) class Person p.size< 160 and super(p) attr_accessor :size end def initialize end @size= 160 module Locked end def canOpen(p) def hasKey p.hasKey() and super(p) true end end end end class Door class ShortLockedDoor< Door def canOpen(p) include Short true include Locked end end def canPass(person) person.size< 210 p= Person.new end d= ShortLockedDoor.new end putsd.canPass(p) Ruby class Door module ShortLocked def canOpen(p) include Short true include Locked end end def canPass(person) class Person person.size< 210 attr_accessor :size end def initialize end @size= 160 module Short end def canPass(p) def hasKey p.size< 160 and super(p) true end end end end module Locked def canOpen(p) p= Person.new p.hasKey() and super(p) d= Door.new end d.extend ShortLocked

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    59 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us