if 0 {[Richard Suchenwirth] 2005-03-23 - I needed this thing to be able to backtrack a display tool, which receives instructions from a pipe on stdin. So I thought up a stack object (framework-less OO :^) with a ''next'' and a ''back'' method to walk up and down the stack, and callbacks for a data source (to extend the stack from) and "drain" (it doesn't really drain anything, it just displays it). The stack only grows over time. } ====== namespace eval ::IOStack {variable nextid 0} #-- The constructor takes the names of the two callbacks, and creates a namespace for the object: proc IOStack::IOStack {source drain} { variable nextid set name [namespace current]::[incr nextid] set vars [list variable stack {} ptr -1 source $source drain $drain] namespace eval $name $vars interp alias {} $name {} [namespace current]::dispatch $name # returns the name } #-- The dispatcher contains the methods, and is aliased to the object name proc IOStack::dispatch {self method args} { import $self stack ptr source drain switch -- $method { next { if {[incr ptr]>=[llength $stack]} {lappend stack [$source]} $drain $ptr:[lindex $stack $ptr] } back {if $ptr {$drain [lindex $stack [incr ptr -1]]}} see {puts [list $ptr $stack] ;#-- for debugging} default {error "bad method $method, must be 'next' or 'back'"} } } #-- Utility for linking variables from a namespace proc import {ns args} { foreach name $args {uplevel 1 [list upvar #0 ${ns}::$name $name]} } ====== if 0 {The last command is the only thing here that resembles vaguely an [OO] "framework", except in size - if you can live without "class", "method" sugar, Tcl's [namespace] facility (for giving an object's instance variables a safe home) and [interp alias] (to redirect the popular $object method arg... way of calling to the generic dispatcher) are perfectly sufficient for rapid OO without any dependencies. There is no explicit destructor - delete all traces of your stack with namespace delete $stack Now testing:} ====== set stack [IOStack::IOStack src drn] #-- Callbacks for "source" and "drain": proc src {} { puts -nonewline "new data: " flush stdout gets stdin } proc drn item { puts "draining $item" } #-- "keyboard event loop" while 1 { puts -nonewline "> " flush stdout gets stdin cmd switch -- $cmd { q {break} + {$stack next} - {$stack back} . {$stack see} } } ====== See also [Skeleton OO] for a variant where methods are implemented as [proc]s. <> Data Structure | Object Orientation