ycl shelf, by PYK, is a simple yet effective dynamic object system similar in some ways to a prototype-based object system.
Are you confused/bored/annoyed by class-based object systems? Then ycl shelf might be the system for you!
shelf provides the functionality needed to work with namespace ensembles as objects in a dynamic object system. In this documentation, shelf signifies the namespace ensemble that is the handle for the object. The ensemble map defines the interface, and commands can be added to the map such that the name of the shelf is automatically passed to the command when called through the ensemble. The map is not limited to such commands, and indeed a new shelf contains in its map commands that don't take the name of the shelf as an argument. A shelf isn't offended in the slightest if the name of the ensemble is passed in some other position, or not at all.
When a shelf is deleted, the associated namespace is also deleted, and vice-versa.
The code footprint of shelf is quite small, and that's partially because components of a shelf have been refactored into other packages in ycl. ycl dupensemble provides the ability to produce new namespaces based on a shelf, and ycl var provides commands such as $, $.exists, and $.locate for reading variables up the hierarchy of shelves that form the basis of the current shelf.
When a new shelf is cloned or spawned, the commands of the map of the new shelf are derived from the map of the current shelf and adjusted so that the name of the new shelf is occurrs in place of the name of the original shelf. This adjustment only happens for items in the lists at the top level at the map, so some care should be taken to form the map such that cloning and spawning has the desired effect
when a shelf is spawned, the namespace of the original shelf is added to the namespace path of the new shelf so that the commands of the original shelf remain available. The shelf a shelf was spawned from is known as the basis, and variables and commands in the basis remain available to the spawned shelf. This mechanism can be used to form a hierarchy of shelves, implementing the prototype pattern.
When a shelf is cloned, the commands and variables in the namespace of the original shelf are actually copied into the cloned shelf, and the namespace of the origanl shelf is not added to the path of the new shelf. A clone is designed to be as indistinguishable as possible from the shelf it was cloned from. Once it is cloned, it can be transformed to taste.
shelf does not currently utilize TclOO, but it certainly might in the future.
A shelf has the following subcommands:
shelf swallow swallow $ airspeed 9 proc fly _ { upvar 0 [$_ $.locate airspeed] airspeed puts "$_ is flying at a speed of $airspeed!" } swallow method fly swallow fly swallow spawn european european $ airspeed 11 european $ airspeed ;# -> 11 european fly
A shelf is commonly given a command named init that serves to set the shelf to some initial state. In contrast with many other object systems, this initialization doesn't occur automatically when a shelf is cloned or spawned. This provides the opportunity to modify a cloned or spawned shelf before initializing it. Like clone and spawn, init commonly returns the name of the shelf, allowing a pattern like this:
[some_shelf spawn newshelf] init key1 val1 key2 val2 ... newshelf dostuff...
To assign the full name of the shelf to a variable, particularly when arranging for a name to be automatically chosen, this becomes:
set newshelf [some_shelf spawn {}] init key1 val1 key2 val2 ... $newshelf dostuff...
A namespace ensemble, or nested namespace ensembles can be used as methods of a shelf. The trick is to use the -parameters switch. Here's an example:
package require {ycl shelf} namespace import [yclprefix]::shelf::shelf shelf {heart of gold} namespace eval generate { namespace ensemble create -parameters _ namespace export * namespace eval infinite { namespace ensemble create -parameters _ namespace export * proc improbability _ { puts [list $_ probability approaching infinity!] } } } {heart of gold} subcmd generate generate [namespace which {heart of gold}] {heart of gold} generate infinite improbability
In the example above, the shelf is passed explicitly to the namespace ensemble command, generate, and the -parameters feature of namespace ensembles takes care of passing the shelf along until it reaches the target method, improbability. Note also that the target command, generate, is resolved relative to the namespace of the shelf at the time it is invoked.
See the implementation of ycl matrix for similar examples.