Class TCircle -parameter circle TCircle instproc getArea {} { set radius [[my circle] radius] expr {$radius*$radius*3.14} } TCircle instproc bounds {} { .... } Class TDrawing -parameter circle TDrawing instproc draw {} { .... } Class Circle -parameter {center radius} Circle init {} { # create nested object for manipulation of circle TCircle create [self]::@manipulator -circle [self] TDrawing create [self]::@drawer -circle [self] } # Using set aCircle [Circle new -center {2 3} -radius 5] $aCircle @drawer drawSo instead of Traits we can build a collaboration of dependent objects and implement the functionality in several classes.
DiscussionThere are also another implementations possible:
- no nested objects so we can change the circle object and reuse TCircle instance for many Circle objects
- do not create TCircle in Circel constructor because of bidirectional dependencies (Circle <-> TCircle)
- create TCircle only if needed
# Business Layer Class Customer -superclass DomainObject # Data Access Layer Class CustomerDAO -superclass DAOBase -parameter {aCustomer} # View Layer Class CustomerView -superclass Form -parameter {aCustomer}One can image that XOTcl can help with Metaclasses and Forwarding to compose objects together and construct on the fly object with suitable consistent interface from composing many object together. It can be good academic exercise. Such implementation provide Traits in XOTclI think the potency of OO is not inheritance but the possibility of building object collaborations that use polymorphism and defined interfaces. Each object in the collaboration depends on several associated object and expect an interface (protocol, contract) from them. To learn how to design such collaborations, the best is to study design patterns. The best known are described in famous book "Design Patterns" from Erich Gamma, Richard Helm, Ralph Johnson and Jon Vlissides.
NEM Your implementation is interesting. It seems somewhat like an actual implementation of traits using aggregation, but without the nice laws of composition. Without forwarding (or some other mechanism), any resolution of conflicts between methods defined by different objects has to performed by clients of the object (e.g. choosing [obj @compa foo] vs [objc @compb foo]). I was actually considering making this change to traits too, as I think it makes some sense to organize methods into sub-ensembles based on interface. e.g. allowing:
myClass instance method foo { ... } { ... } ;# uses "instance" trait (equiv to instproc). myClass object method bar { ... } { ... } ;# equiv to [myClass proc] in current XOTcl.This is essentially the same as your aggregation example, but with the components named after the interface that they provide. You could also allow [instance method myClass foo...] etc as alternative syntax. In traits, the methods are all collapsed into a single, flat namespace in the final composition. The reasoning for this was to limit exposure of implementation details (that the object is composed of traits and not a monolithic code repository). However, I don't think that is really much of a concern, as the traits should expose individual interfaces, and so allowing the client to see which traits are part of the composition seems like just making explicit which interfaces are supported, which seems reasonable. So, it looks like XOTcl can do traits reasonably well, which satisfies me. I may do an implementation of traits with dicts and lambdas, as I think that will also work quite well, and dicts behave in the same way as traits regarding composition (they are sets, discriminating by name only).
Artur Trzewik I have taken a look into my smart "Design Patterns" book and have found that the problem is quite similar to "Decorator Pattern". We can consider that from another side. TCircle extend Circle with special functionality but it behaves like Circle. The book describe this pattern implementation as aggregation. Gustaf Neumann and Uwe Zdun (Authors of XOTcl) have written many publications about OO patterns. In [1] they also describe decorator pattern implemented by per-object mixins.I my opinion there are two different needs in oo-design.
- Object client expect one simple consistent API and want no problems with creating objects.
- Object maintainer want a code good for economic implement and reuse
- J2EE - Component is EJB (so it is special object)
- C# - Component is an assembly (set of classes, types)
- C# (another try) - Component is Class that has interface IComponent (which is quite poor anyway)
- hide creation of objects collaborations.
- create single flat public api to one object for object collaboration (by using forwarding, mixins or filters)
- check objects contracts
- resolve some method invocation problems
GN Note that (1) argue that traits are an alternate approach for behavior composition to mixins, to overcome the "total composition ordering" limitation of mixins. Actually, NX, the Next Scripting Language provides already some native support for traits (see [2] and [3]). Note as well, that the term "mixin" is not consistently used in different languages. Mixins in XOTcl are decorator style mixins, while Ruby (or Scala) uses mixins similar to multiple inheritance (see [4])(1) S. Ducasse, O. Nierstrasz, N. Schärli, R. Wuyts, A. Black: Traits: A Mechanism for Fine-grained Reuse, ACM transactions on Programming Language Systems, Vol 28, No 2, March 2006