'''eos''': ensemble object system ([neo] is a much better name, [RS] was faster ...) This system is closely related to [neo], and inspired by [NEM]'s '[Using namespace ensemble without a namespace]'. ---- '''eos''' is a slot based system. It provides ''cloning''. ''To be continued ...'' namespace eval eos { variable nobjs0 namespace export * # ::eos:: Create a new object proc {} args { if {[set len [llength $args]] > 1} { set cmd [lindex [info level 1] 0] return -code error "wrong # args: should be \"$cmd ?objname?\"" } if {$len == 1} { set name [lindex $args 0] if {[string range $name 0 1] ne "::"} { set ns [uplevel 1 [list namespace current]] if {![llength $ns]} {set ns ::} set name $ns$name } } else { variable nobjs set name ::eos::OBJ[incr nobjs] } uplevel \#0 [list namespace ensemble create \ -command $name \ -map {} \ -unknown ::eos::unknown\ ] return $name } proc const v {return $v} # The proc unknown defines the default slots, ie, the "class" of the # object. It processes all not-found instances, as it is the -unknown # option in the ensemble as set above. # A new "class" just requires defining a new unknown processor, and setting # it as the -unknown processor in the ensemble. proc unknown {obj cmd args} {list ::eos::*$cmd $obj} # # Define the default functions for the "class": by convention, the names # start with '*'. These are found by the utility function "unknown" above # proc *config {self {new {}}} { set map [namespace ensemble configure $self -map] if {$new eq {}} { return $map } namespace ensemble configure $self -map [dict merge $map $new] } proc *slot {self slot value} { set map [namespace ensemble configure $self -map] dict set map $slot $value namespace ensemble configure $self -map $map } proc *clear {self slot} { set map [namespace ensemble configure $self -map] set map [dict remove $map $slot] namespace ensemble configure $self -map $map } proc *method {self name params body {ns ::}} { set params [linsert $params 0 self] *slot $self $name ::apply [list $params $body $ns] $self } proc *value {self slot value} { *slot $self $slot ::eos::const $value return $value } proc *clone {self args} { # Assumes that $self only appears at the end (as in methods) if {[llength $args] > 1} { return -code error "wrong # args: should be \"$self clone ?cloneName?\"" } set new [uplevel 1 [list ::eos:: {expand}$args]] set conf [namespace ensemble configure $self] set conf [dict remove $conf -namespace] dict for {slot meth} [dict get $conf -map] { if {[lindex $meth end] eq $self} { dict set conf -map $slot [lreplace $meth end end $new] } } namespace ensemble configure $new {expand}$conf return $new } proc *delete {self} { uplevel 1 [rename $self {}] } } ---- % ::eos:: toggle ::toggle % toggle value state 1 1 % toggle method activate {} {$self value state [expr {![$self state]}]} % time {toggle activate} 1000 73.251 microseconds per iteration % # avoiding the default method 'value' (found by unknown) ... % toggle method activate {} {$self setvalue state [expr {![$self state]}]} % toggle method setvalue {slot v} {::eos::*slot $self $slot ::eos::const $v; set v} % time {toggle activate} 1000 54.066 microseconds per iteration % toggle method self {} {return $self} % toggle self ::toggle % time {toggle self} 1000 8.049 microseconds per iteration % Dispatch is very fast (but getting the value of constant slots less so). For comparison with standard '''proc''' dispatching: % proc a x {return $x} % time {a dummy} 1000 5.287 microseconds per iteration ---- Note that delegation is easy (to other '''eos''' objects, or actually to any other command or object): it suffices to define the default method proc ::eos::*delegate {source method target args} { set target [uplevel 1 [list namespace which -command $target]] *slot $source $method $target {expand}$args } To use this in the above example, one could have defined toggle method activate {} {$self setstate [expr {![$self state]}]} toggle delegate setstate ::eos::*slot ::toggle state ::eos::const However, this is properly the field for an extension of the system: delegation should be combined with proper lifetime management of whatever sub-object might be created for the purpose of delegation. ---- [Category Object Orientation]