namespace eval neo {variable version 0.1}
proc neo::new {name _where_ args} {
set map [dict create]
foreach {slot = value} $args { dict set map $slot $value }
namespace ensemble create -command $name -map $map
}
proc neo::slot {object slot = command args} {
set map [config $object -map]
dict set map $slot [linsert $args 0 $command]
config $object -map $map
}
proc neo::method {object name params body} {
set params [linsert $params 0 self]
slot $object $name = ::apply [list $params $body ::] $object
}
proc neo::const val { return $val }
interp alias {} neo::config {} namespace ensemble configure
proc neo::delete name {rename $name {}}#-- So far for neo the "system", the rest is tests and demos:
proc rect {canv x0 y0 x1 y1} { #-- a constructor
set id [$canv create rect $x0 $y0 $x1 $y1]
set obj [neo::new $canv.rect$id where \
id = [list const $id] \
coords = [list ::$canv coords $id]]
neo::slot $obj canvas = const $canv
set obj
}
catch {destroy .c} ;# good for repeated sourcing
pack [canvas .c]
set r [rect .c 20 20 100 100]
puts "id = [$r id], coords = [$r coords]"
neo::slot $r type = const "rectangle" ;#-- object-specific slot
puts "$r is a [$r type]"
neo::method $r width {} {
lassign [$self coords] x0 y0 x1 y1
expr {abs($x1-$x0)}
}
neo::method $r height {} {
lassign [$self coords] x0 y0 x1 y1
expr {abs($y1-$y0)}
}
puts height:[$r height],width:[$r width]
neo::method $r area {} { expr {[$self width] * [$self height]} }
puts "area = [$r area]"
puts [neo::config $r -map]RS So how are ensembles suitable for representing objects?
- one object corresponds to one command
- The popular $obj method arg... calling style is directly supported
- dispatching and introspection are built in (in fast C code)
- objects are easily serialized by lugging the map around (reminiscent of TOOT, also by NEM)
- variables and methods are unified, as if we had no variables :) Getters go by name (e.g. [$self type]), setters just use neo::slot, e.g neo::slot $self type = const square
- inheritance isn't supported yet, but that could be added (to the map)
MS proposes a small modification to ::neo::new, that allows the class methods (slot, method, config, delete) to be available in oo manner. The first modification is taking it out of the ::neo namespace (as it does not work properly as a class method), the second is to define an unknown handler that defines the procs in ::neo as object methods:
proc neo {name _where_ args} {
set map [dict create]
foreach {slot = value} $args { dict set map $slot $value }
namespace ensemble create -command $name -map $map \
-unknown {::apply {{obj cmd args} {list ::neo::$cmd $obj}}}
}
he novelty in here is that we can do e.g.
% neo test w
::test
% test method shout {} {puts "This is $self"}
% test shout
This is ::test
% test scream
invalid command name "::neo::scream"
% proc ::neo::scream obj {puts "THIS IS $obj"}
% test scream
THIS IS ::test
% test method scream {} {puts "$self does not scream"}
% test scream
::test does not scream
% test configure
invalid command name "::neo::configure"
% test config
-map {scream {::apply {self {puts "$self does not scream"} ::} ::test} shout {::apply {self {puts "This is $self"} ::} ::test}} -namespace :: -prefixes 1 -subcommands {} -unknown {::apply {{obj cmd args} {list ::neo::$cmd $obj}}}See also eos for a closely related system.

