# Listing of doc/example-scripts/traits-composite.tcl

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