aitcs - Array in the Command's Shadow
Array in the Command's Shadow provides a convenient way to access and manipulate arrays in namespaces by offering a higher level of abstraction for certain array operations.
An AitCS is an array with an associated set of commands that access or manipulate the array. Array accesses are via commands instead of referring to the array as a variable. The array is still an array, but there is now a set of commands that "know" the array.
An AitCS is designed to be used where a program would normally use global or namespace variables to hold configuration, state, widget paths, temp values, etc.
As opposed to namespace ensembles and objects, AitCS doesn't create one command and then dispatch on operators (subcommands). Instead, one command is created for each operator, with the name of the operator attached to the command.
For get/set operations, the command (the name of the AitCS) is used like Tcl's [set] command.
Regular:
namespace eval myns { variable myarr set myarr(a) 1 proc myproc1 {} { variable myarr if {![info exists myarr(b)]} { set myarr(b) [expr {$myarr(a) + 1}] } } proc myproc2 {} { variable myarr puts $myarr(b) } myproc1; myproc2 }
AitCS:
namespace eval myns { aitcs new myarr myarr a 1 proc myproc1 {} { if {![myarr? b]} { myarr b [expr {[myarr a] + 1}] } } proc myproc2 {} { puts [myarr b] } myproc1; myproc2 }
An AitCS is one array and nine commands. The commands access and manipulate the array itself.
An AitCS+ is one array and twelve commands. An AitCS+ is identical to an AitCS, with the exception of three additional commands. The additional commands access and manipulate the contents of array elements.
The array is created in a namespace and the commands are created in a (possibly different) namespace.
All references to array variables, elements, or commands produced by AitCS are fully qualified.
Destroying the array by any means other than by the "---" operator will only destroy the array, not the commands. There are no traces or other connections between the commands and the array; the commands only know the array's name.
An AitCS can have a random name or a user-supplied name. The actual array name is a concatenation of the name, a random string of characters, and some underscores for good measure. This is like an opaque pointer in that a human doesn't need to know the actual name of the array. Having randomly-generated names can help with writing fewer bugs as code will be less dependent on hardcoded variable names.
AitCS helps to reduce complications with namespaces, makes for cleaner code, and saves typing.
AitCS works with Jim as well as with Tcl.
Creates a new array in the namespace variable_namespace and creates commands to manipulate the array in the namespace command_namespace.
If the name isn't supplied or is an empty string then the name will be set to a string of six random characters in the range a-z. An error will be returned if a unique random command in the command_namespace can't be created after one thousand attempts. This should never happen?
If the variable_namespace isn't supplied or is an empty string then it will be set to the caller's namespace.
If the command_namespace isn't supplied or is an empty string then the command_namespace will be set to the variable_namespace.
The array will be created as "variable_namespace::__name__cccccc_" where "cccccc" is six random characters in the range a-z.
If the command already exists or any of the required namespaces don't exist then an error will be returned and neither array nor commands will be created.
Initial values are set from key value ... if supplied.
Creates an array variable in the variable_namespace and associated commands in the command_namespace.
Returns the fully qualified name of the array's set/get command.
Options
Returns a list of all the AitCS operators.
Returns a list of all the AitCS+ operators.
AitCS commands are created in the command_namespace and are based on the name supplied when the AitCS was created.
The following commands are common to an AitCS and an AitCS+.
Brings the array into existence in the current context. This is upvar #0 varname name. From then on in the current context the array can be referenced by name. Returns an empty string. Nickname: Make Exist.
Gets the value of one element of the array or sets the value of one or more elements of the array. The value(s) for the key(s) will be set using array set. Returns the value at key. Nickname: Get/Set.
Returns true if the key exists in the array or false if the key doesn't exist in the array. If the key exists and myVar is supplied and is not an empty string then the variable it names will be set in the caller's context to the value at key. Nickname: Exists.
Removes key(s) from the array. The array unset command is used, allowing key(s) to contain wildcards. It isn't an error if a key doesn't exist in the array. Returns an empty string. Nickname: Unset.
Returns the value at key if it exists, otherwise returns default, or an empty string if default isn't supplied. If myVar is supplied and is not an empty string then the variable it names will be set in the caller's context to the returned value. Nickname: Get With Default.
Returns the fully namespace qualified name of the array if no key supplied or if key is an empty string, otherwise returns the fully namespace qualified name of the array and the element key. Nickname: Variable Reference.
Returns the fully namespace qualified command. Nickname: Command Reference.
The key should be another AitCS. Permits "nesting". Calls are chained. Nickname: Struct Dereference.
Unsets the array and deletes all the commands. Returns an empty string. Nickname: Destroy.
The following commands are only provided by an AitCS+.
Every key is set to value. Returns value. Nickname: Setto.
Every value is lappended to the element at key. Returns the value at key. Nickname: Lappend.
Increments the value at key by all incr arguments (default 1). Returns the value at key. Nickname: Incr.
# Set/Get/Variable Reference # Save a widget and link a textvariable aitcs new rec aitcs new gui set fld preference rec $fld Tcl gui $fld [entry .e -textvariable [rec& $fld]] [gui $fld] insert end /Tk string length [rec preference]; # 6 # Get/Set aitcs new things things a 3 things b [expr {[things a] + 2}] things c [expr {[things b] * [things a]}] things c; # 15 # Exists aitcs new colours colours red #FF0000 colours? red; # 1 colours? green; # 0 colours? red color1; # 1 info exists color1; # 1 set color1; # #FF0000 colours? green color2; # 0 info exists color2; # 0 # Setto/Exists/Unset/Variable Reference aitcs+ new fruits fruits= apple orange pear apricot 0 if {![fruits? peach]} { fruits= peach 0 } array names [fruits&]; # {apple orange pear apricot peach} fruits- p* a* array names [fruits&]; # {orange} # Get With Default aitcs new things things are good things^ are ok; # good things^ be ok; # ok things^ willbe; # Empty string things^ is nice here; # nice, and var here is set to nice # Lappend aitcs+ new store store this one store+ this two three four five store this; # {one two three four five} # Incr aitcs+ new counters counters cycles 0 counters+= cycles counters+= cycles 2 counters+= cycles 3 -4 1 counters cycles; # 3 # Make Exist/Exists aitcs new cow cow! set cow(sound) moo if {[cow? sound] && $cow(sound) eq "moo"} { puts "Standard English Cow" } # Command Reference/Variable Reference/Incr aitcs new callback callback count 0 after 1000 [list [callback&&]+= count] vwait [callback& count] callback count; # 1 # Struct Dereference/Random Name/Initial Values aitcs new animals animals dog [aitcs new {} {} {} says woof likes cat] animals cat [aitcs new {} {} {} says meow likes dog] animals home [list dog cat] set res "" foreach animal [animals home] { append res $animal " says " [animals-> $animal says] append res " likes " [animals-> $animal likes] append res " who says " [animals-> [animals-> $animal likes] says]\n } set res # dog says woof likes cat who says meow # cat says meow likes dog who says woof # Struct Dereference aitcs+ new outer aitcs+ new inner aitcs+ new innest inner count 6 innest things [list] innest+ things 1 2 outer member inner inner item innest outer-> member+= count 2; # 8 outer-> member-> item+ things 3 4; # {1 2 3 4} outer-> member-> item^ name; # Empty string # Destroy aitcs+ new tmp tmp count 5 tmp+= count -1 tmp count; # 4 set fqarr [tmp&] info exists $fqarr; # 1 tmp--- info exists $fqarr; # 0 tmp count; # <error>
The inspiration came from being tired of having to use the variable command in almost all the commands in a namespace when often in a given command there is usually interest in only a few items of the "global" state.
To maintain the smallest possible set of commands, the necessity and usefulness of each command was carefully considered before including it in AitCS. All commands were written and tested to be as fast as possible.
The "&" operator was inspired by C: obtaining a "reference" to an element of an array. The "&&" operator was inspired the "&" operator. The "^" operator was inspired by the XOR operator: result is one or the other. The "->" operator was inspired by C structures. Originally "." but changed for greater readability. The "!" operator is excitement: something has just come into existence! The "?" operator is the obvious choice for its function. The "-" operator generally means "remove something". The "+" operator generally means "add something". The "+=" operator was inspired by C. For the "---" (destroy) operator, three dashes were chosen because two would be too easily confused with C's "--", and it is reminiscent of "===" in other languages, which carries a meaning of "really serious this time".
In the interest of speed, the AitCS commands don't check anything. Errors reported will be errors occurring inside the AitCS commands. For example, attempting to retrieve the value of a nonexistent element will result in a "no such element in array" error somewhere within the AitCS command.
array, command, eagle, namespace, snake
Programming tools
Copyright © 2022 Stuart Cassoff <stwo@users.sourceforge.net>