Solving Traits problems with standard OO

Author: Artur Trzewik

Traits page describes know design problem in OO. How to provide functionality for object that should be reused but can not be implemented by heritage. Often it is design decision do not implement some functionality in object itself because it would overload the object interface.

Here a design alternative how avoid such problem by using old good object association or in this case aggregation.

In the original idea traits are set of methods, which can be added to object and have defined requirement for object interface. In Java or C# we can define such requirement as Interface in XOTcl we can only document it or write some policies as XOTcl precondition.

The idea is to have many objects for each functionality and base object only for as central data container.

Example taken from Traits publication

   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 draw

So instead of Traits we can build a collaboration of dependent objects and implement the functionality in several classes.


There are also another implementations possible:

  1. no nested objects so we can change the circle object and reuse TCircle instance for many Circle objects
  2. do not create TCircle in Circel constructor because of bidirectional dependencies (Circle <-> TCircle)
  3. create TCircle only if needed

In can observe that is last years OO-programmers tends to split functionality into many classes that becomes names as Controller or Action. So not to program all functionality in one Class (or Class heritage) itself. Overloaded Classes becomes Antipatterns (the blob or ghost class).

The proven architecture is to define several of layers and provide for each layer own class set. In such models often the classes are build after chosen name pattern. Here example of 3-layer design.

   # 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 XOTcl

I 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 [L1 ] they also describe decorator pattern implemented by per-object mixins.

I my opinion there are two different needs in oo-design.

  1. Object client expect one simple consistent API and want no problems with creating objects.
  2. Object maintainer want a code good for economic implement and reuse

There are till now not good solution for fulfill these needs in mainstream OO.

Similar consideration we have also in EJB Session Facade Pattern. Session Beans are used as single entry point for public API and forwards the calls to Entity Beans, which are hidden from client. Implementing this in JAVA is quite laborious because we must write many simple forward call methods. So a client view is simple object but behind it is a objects collaboration. There are still definition problems in Java (OO) world about what is component API and how to define it.

  1. J2EE - Component is EJB (so it is special object)
  2. C# - Component is an assembly (set of classes, types)
  3. C# (another try) - Component is Class that has interface IComponent (which is quite poor anyway)

I can image that with XOTcl is possible to create a framework that can

  1. hide creation of objects collaborations.
  2. create single flat public api to one object for object collaboration (by using forwarding, mixins or filters)
  3. check objects contracts
  4. resolve some method invocation problems

Such framework will be useful only in bigger projects (Megawidgets) or good for academic purposes.

In XOTcl libs are many hight abstraction level implementation for some patterns (Adaptor, Composite, ...). It needs some times to understand them.

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 [L2 ] and [L3 ]). 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 [L4 ])

(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