# Implementation study based on 
#
#   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
#
# Example in Fig 12: ReadStream and Trait tReadStream
#
# In this example, traits are used to extend classes and other traits.

package require nx::test
package require nx::trait

#
# Create a simple trait called +tReadStream+ which provides the
# interface to a stream. In contrary to a composite trait, a simple
# trait does not inherit from another trait.
#
nx::Trait create tReadStream {
  #
  # Define the methods provided by this trait:
  #
  :public method atStart {} {expr {[:position get] == [:minPosition]}}
  :public method atEnd {} {expr {[:position get] == [:maxPosition]}}
  :public method setToStart {} {set :position [:minPosition]}
  :public method setToEnd {} {set :position [:maxPosition]}
  :public method maxPosition {} {llength ${:collection}}
  :public method on {collection} {set :collection $collection; :setToStart}
  :public method next {} {
    if {[:atEnd]} {return ""} else {
      set r [lindex ${:collection} ${:position}]
      :nextPosition
      return $r
    }
  }
  :public method minPosition {} {return 0}
  :public method nextPosition {} {incr :position 1}
  
  # This trait requires a method "position" and a variable
  # "collection" from the base class. The definition is incomplete in
  # these regards.

  :requiredMethods position
  :requiredVariables collection
}

# Define the class +ReadStream+ with properties +position+ and
# +collection+ that uses the trait. The method +require trait+ checks the
# requirements of the trait and imports the methods into +ReadStream+.

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

# Create an instance of the class +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
