presentation of traits
DESCRIPTION
Traits are a simple composition mechanism for structuring object-oriented programs. A Trait is essentially a parameterized set of methods; it serves as a behavioral building block for classes and is the primitive unit of code reuse. With Traits, classes are still organized in a single inheritance hierarchy, but they can make use of Traits to specify the incremental difference in behavior with respect to their superclasses.TRANSCRIPT
Lifting your favorite language with Traits
Alexandre BergelRMoD team, INRIA,
Lille, [email protected]
!"#$
Outline
1. Limitation of single inheritance
2. Traits
3. Retrospective
4. Freezable & Stateful
5. Conclusion
Stream in Squeak
• Example of a library that has been in use for almost 20 years
• Contains many flaws in its design
Stream in Squeak
atEndclosecontentsdo:flushnextnext:next:put:nextPut:nextPutAll:upToEnd
Stream
atEndcontentsisEmptynext:peekpositionposition:resetsetToEndskip:skipTo:upTo:upToEnd
collectionpositionreadLimit
Positionable
Stream
nextnext:nextPut:sizeupTo:upToEnd
ReadStream
contentsflushnextnextPut:nextPutAll:position:resetsetToEndsizespacecr
writeLimitWriteStream
closecontentsnextnext:
ReadWriteStream
atEndcloseflushfullNamenextnext:nextPut:nextPutAll:peekpositionposition:resetsetToEndsizeskip:upTo:upToEnd
rwmodenamefileIDbuffer1
FileStream
Methods too high
atEndclosecontentsdo:flushnextnext:next:put:nextPut:nextPutAll:upToEnd
Stream
atEndcontentsisEmptynext:peekpositionposition:resetsetToEndskip:skipTo:upTo:upToEnd
collectionpositionreadLimit
Positionable
Stream
nextnext:nextPut:sizeupTo:upToEnd
ReadStream
contentsflushnextnextPut:nextPutAll:position:resetsetToEndsizespacecr
writeLimitWriteStream
closecontentsnextnext:
ReadWriteStream
atEndcloseflushfullNamenextnext:nextPut:nextPutAll:peekpositionposition:resetsetToEndsizeskip:upTo:upToEnd
rwmodenamefileIDbuffer1
FileStream
nextPutAll: aCollection aCollection do: [:v| self nextPut: v]. ^ aCollection
Methods too high
• The nextPut: method defined in Stream allows for element addition
• The ReadStream class is read-only
• It therefore needs to “cancel” this method by redefining it and throwing an exception
Unused state
atEndclosecontentsdo:flushnextnext:next:put:nextPut:nextPutAll:upToEnd
Stream
atEndcontentsisEmptynext:peekpositionposition:resetsetToEndskip:skipTo:upTo:upToEnd
collectionpositionreadLimit
Positionable
Stream
nextnext:nextPut:sizeupTo:upToEnd
ReadStream
contentsflushnextnextPut:nextPutAll:position:resetsetToEndsizespacecr
writeLimitWriteStream
closecontentsnextnext:
ReadWriteStream
atEndcloseflushfullNamenextnext:nextPut:nextPutAll:peekpositionposition:resetsetToEndsizeskip:upTo:upToEnd
rwmodenamefileIDbuffer1
FileStream
Unused state
• State defined in the super classes are becoming irrelevant in subclasses
• FileStream does not use inherited variables
Multiple inheritance simulation
atEndclosecontentsdo:flushnextnext:next:put:nextPut:nextPutAll:upToEnd
Stream
atEndcontentsisEmptynext:peekpositionposition:resetsetToEndskip:skipTo:upTo:upToEnd
collectionpositionreadLimit
Positionable
Stream
nextnext:nextPut:sizeupTo:upToEnd
ReadStream
contentsflushnextnextPut:nextPutAll:position:resetsetToEndsizespacecr
writeLimitWriteStream
closecontentsnextnext:
ReadWriteStream
atEndcloseflushfullNamenextnext:nextPut:nextPutAll:peekpositionposition:resetsetToEndsizeskip:upTo:upToEnd
rwmodenamefileIDbuffer1
FileStream
Multiple inheritance simulation
• Methods are duplicated among different class hierarchies
Class responsibilities
• Too many responsibilities for classes
- object factories
- group methods when subclassing `
Class schizophrenia?
• Too many responsibilities for classes
- object factories => need for completeness
- group methods when subclassing => need to incorporate incomplete fragments
Traits
TCircleareaboundsdiameterhash...
radiusradius:centercenter:
• Traits are parameterized behaviors- traits provide a set of methods - traits require a set of methods - traits are purely behavioral
Class = Superclass + State + Traits + Glue Methods
• Traits are the behavioral building blocks of classes
Generic propertiesObject
Component Geometrical
RectangleWidget
setX1(...)setY1(...)
RectangleShape
setX1(...)setY1(...)TRectangle
TColorx1, y1, x2, y2 point1, point2
TRectangle
TColor
...
Composition rules
Class methods take precedence over trait methods
ColoredCircle
TColorhuergb
draw
ColoredCircle
TColorhuergb
TCircledrawradiusdrawdraw
TCircledrawradius
Conflicts are explicitly resolved
• Override the conflict with a glue method
- Aliases provide access to the conflicting methods
• Avoid the conflict
- Exclude the conflicting method from one trait
ColoredCircle
TColorhash
TCirclehashhash -> circleHash
hash
ColoredCircle
TColorhash
TCirclehashhash hash -> circleHash
hash -> colorHash
Flattening property
ColoredCircle
TColor
TCircledraw
rgb
draw
hue
radius
Object
ColoredCircle
Object
rgbhue
radius
draw
equivalentStructured view Flat view
Stream revisited
do:nextMatchFor:next:peekFor:skip:skipTo:upTo:upToEndupToElementSatisfying:
atEndnextpeekoutputCollectionClass
TGettableStream
atEndatStartbackcloseisEmptyposition:resetsetToEnd
positionsetPosition:size
TPositionableStream
nextPutAll:next:put:print:flush
nextPut:TPuttableStream
Core
binarycloseclosedisBinaryisClosedisStream
TStream
backbackUpTo:match:nextDelimited:skip:
TGettablePositionableStream TPuttablePositionableStream
writeBack
@ {#basicBack->#back}
Retrospective
• International recognition- Fortress- Slate- Perl 6- Squeak
• Numerous type systems- Nierstrasz’06- Fisher&Reppy’03, Reppy & Turon’06- Drossopoulou’05
StatefulTraits
• Alexandre Bergel, Stéphane Ducasse, Oscar Nierstrasz and Roel Wuyts, “Stateful Traits,” Advances in Smalltalk — Proceedings of 14th International Smalltalk Conference (ISC 2006), LNCS, vol. 4406, Springer, August 2007, pp. 66-90.
• Alexandre Bergel, Stéphane Ducasse, Oscar Nierstrasz and Roel Wuyts, “Stateful Traits and their Formalization,” Journal of Computer Languages, Systems and Structures, vol. 34, no. 2-3, 2008, pp. 83-108
Traits limits
• Trait users should define missing traits state
• Important required methods and required state are mixed
• Boilerplate glue code
• Propagation of required accessors
TSyncReadWritelockinitializesyncReadsyncWrite
readwritelock:lock
SyncFilelocklock:lockreadwrite
SyncStreamlocklock:lockreadwrite
SyncSocketlocklock:lockreadwrite
syncRead | value | self lock acquire. value := self read. self lock release. ^ value
syncWrite | value | self lock acquire. value := self write. self lock release. ^ value
Duplicated code
Use of trait
initialize super initialize. self lock: Lock new
Stateful traits
• Instance variables are per default private to the trait
• Via composition
• Composing classes may get access to state
• Composing classes may merge the accessed state
By default state is private
T1
getXT1
setXT1:
x
T2
getXT2
setXT2:
x
C
getX
setX:
x
c := C new.c setXT1: 1.c setXT2: 2.c setX: 3.
{ Now: c getXT1 = 1 c getXT2 = 2 c getX = 3 }
But remain accessible still
@@{ xFromT1 -> x }T1
getXT1
setXT1:
x
@@{ xFromT2 -> x }
c := C new.c setXT1: 1.c setXT2: 2.
{ Now: c getXT1 = 1 c getXT2 = 2 c sum = 3 }
sum
^ xFromT1 + xFromT2
T2
getXT2
setXT2:
x
sum
C
Variables may be merged
T1
getX
setX:
x
T2
getY
setY:
y
C
getW
setW:
@@{w -> x}
@@{w -> y}
c := C new.c setW: 3.
{ Now: c getX = 3 c getY = 3 c getW = 3 }
Analysis• Traits and state reconciled
Traits are completeStateless traits are just a special case of stateful traitsNo accessor requiredNo boiler plate code
Flattening property can be rescued using instance variable mangling
State is private but can be made accessible at composition
Freezable Traits
• Stéphane Ducasse, Roel Wuyts, Alexandre Bergel and Oscar Nierstrasz, “User-Changeable Visibility: Resolving Unanticipated Name Clashes in Traits,” Proceedings of 22nd International Conference on Object-Oriented Programming, Systems, Languages, and Applications (OOPSLA'07), ACM Press, New York, NY, USA, October 2007, pp. 171—190.
Trait limits
Composer
T1foo {self x}x {^ 'T1'}
T2bar {self x}x {^ 'T2'}
trait trait composition
• Methods may conflict while they are private to the traits
• You can only have one x in Composer: either T1x, T2x or Cx
Method Visibility
Composer
Freezing T1 x
Composer new foo -> 'T1'Composer new bar -> 'T2'Composer new x -> 'T2'
T1+ foo {self x}+ x { ^ 'T1'}
T2+ bar {self x}+ x { ^ 'T2'}
T1 freeze x Composer
Freezing T2 x and T2 x
Composer new foo -> 'T1'Composer new bar -> 'T2'Composer new x -> Error
T1+ foo {self x}+ x { ^ 'T1'}
T2+ bar {self x}+ x { ^ 'T2'}
T2 freeze x
+ x {^'C'}Composer
T1+ foo {self x}- x { ^ 'T1'}
T2+ bar {self x}- x { ^ 'T2'}
Conflict resolution via method redefinition in Composer
Composer new foo -> 'C'Composer new bar -> 'C'Composer new x -> 'C'
Composer
Unfreezing T1 x and freezing T2 x
Composer new foo -> 'T1'Composer new bar -> 'T2'Composer new x -> 'T1'
T1+ foo {self x}- x { ^ 'T1'}
T2+ bar {self x}+ x { ^ 'T2'}
T1 unfreeze x
T2 freeze x
T1 freeze x
T1 unfreeze xT2 unfreeze x
Map
Traits
Encapsulation policies
Stateful traits
Freezable traits
Pure traitslanguageecoop’03
oopsla’03icse’04toplas
ecoop’04
Jour. of Comp. Lang., Sys. Struct.
oopsla’07
Conclusion
• Traits are interesting constructs
• But
- Need more experience building complex software
- Do we get patterns (composition vs. inheritance)?
• Less operators?
• A trait-based only language
A trait is:-a group of methods
-may be composed with other traits- may be used by classes
in order to share behavior
http://www.iam.unibe.ch/~scg/Research/Traits/
or simply ask google