traits-composite.html

Implementation study based on

  1. 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

Fig 13: tReadStream and tWriteStream as composite traits

In this example, traits are used to extend classes and other traits (called then composite traits).

package req nx::trait

Create a Trait called tPositionableStream

nx::Trait create tPositionableStream {
  #
  # Define the methods provided by this trait:
  #
  :public method atStart {} {expr {[:position] == [:minPosition]}}
  :public method atEnd {} {expr {[:position] == [:maxPosition]}}
  :public method setToStart {} {set :position [:minPosition]}
  :public method setToEnd {} {set :position [:maxPosition]}
  :public method maxPosition {} {llength ${:collection}}
  :public method minPosition {} {return 0}
  :public method nextPosition {} {incr :position 1}

  # The trait requires a method "position" and a variable "collection"
  # from the base class or other traits. The definition is incomplete
  # in these regards

  :requiredMethods position
  :requiredVariables collection
}

Create a composite trait called tReadStream based on the trait tPositionableStream:

nx::Trait create tReadStream {
  #
  # Methods provided by this trait:
  #
  :public method on {collection} {set :collection $collection; :setToStart}
  :public method next {} {
    if {[:atEnd]} {return ""} else {
      set r [lindex ${:collection} ${:position}]
      :nextPosition
      return $r
    }
  }

  # This trait requires these methods:
  :requiredMethods {setToStart atEnd nextPosition}

  # Require the trait "tPositionableStream"
  :require trait tPositionableStream
}

Create a composite trait called tWriteStream based on the trait tPositionableStream:

nx::Trait create tWriteStream {
  #
  # Methods provided by this trait:
  #
  :public method on {collection} {set :collection $collection; :setToEnd}
  :public method nextPut {element} {
    lappend :collection $element
    :nextPosition
    return ""
  }

  # This trait requires these methods:
  :requiredMethods {setToEnd nextPosition}

  # Require the trait "tPositionableStream"
  :require trait tPositionableStream
}

Define a class ReadStream with properties position and collection that uses the composite trait tReadStream:

nx::Class create ReadStream {
  :property {collection ""}
  :property -accessor public {position 0}
  :require trait tReadStream
}

Create an instance of ReadStream:

ReadStream create r1 -collection {a b c d e}

Test the behavior of the composed class:

% r1 atStart
1
% r1 atEnd
0
% r1 next
a
% r1 next
b