State-specific behavior in NX

A small design study to show how to implement state specific behavior in nx via per-object mixins. Using mixins has the advantage that this approach does not face the "self problem" of delegation, where the object has to be passed as argument to refer to the object's content.

# 
# Implementing state specific behavior via per-object mixins
#
package require nx
package require nx::test

#
# Class: StateMachine 
#
# Define a minimalistic state machine that will always be initially in
# a state named "initial". The states are defined as classes for easy
# switching behavior and they are aggregated into the application
# class for locality.
#
nx::Class create StateMachine {
  :public method current_state {} {:info object mixin classes}
  :method transition {newState} {:object mixin [:info class]::$newState}
  :method init {} {:object mixin [:info class]::initial}
}

#
# MetaClass: State
# 
# The meta class provides means for generic state handling (e.g. via
# "info instances") and for better describing the intended semantics
# of these classes.
#
nx::Class create State -superclass nx::Class 

#
# Application Class: conference 
#
nx::Class create conference -superclass StateMachine {
  State create [self]::initial {
    :public method apply_program_committee {} {return ok}
    :public method submit_paper {} {return not-yet}
    :public method publish-cfp {} {:transition cfp-open}
  }
  State create [self]::cfp-open {
    :public method apply_program_committee {} {return too-late}
    :public method submit_paper {} {return ok}
  }
}

conference create tcl2014
? {tcl2014 current_state} "::conference::initial"
? {tcl2014 apply_program_committee} "ok"
? {tcl2014 submit_paper} "not-yet"
tcl2014 publish-cfp

? {tcl2014 current_state} "::conference::cfp-open"
? {tcl2014 apply_program_committee} "too-late"
? {tcl2014 submit_paper} "ok"