ycl shelf, by PYK, is a simple yet effective dynamic object system similar in some ways to a prototype-based object system.
PYK 2017-05-01: Release of verion 0.2. Improved switch method, propagation of destructors to cloned and spawned shelves.
Despite its small size, ycl shelf is fully featured and ready for use in real projects. It eschews the more widespread class paradigm in favour of the ability to spawn or clone existing objects.
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. commands can be added to the shelf such that the name of the shelf is automatically passed to the command when called through the ensemble. The shelf is not limited to such commands, and indeed an off-the-shelf shelf contains 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 ensemble duplicate provides the ability to produce the namespaces for a new 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 commans for the new shelf are derived from those of the current shelf and adjusted so that they reflect the new shelf instead.
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, but this is generally only useful for utilties, i.e., routines that don't need to know the name of the current shelf. The shelf a shelf was spawned or cloned 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 original 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 might in the future.
The primordial shelf has the following subcommands:
package require {ycl shelf util}
shelf spawn 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 tailor 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 shelf} namespace import [yclprefix]::shelf::shelf shelf spawn {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} method generate {heart of gold} generate infinite improbability
In the example above, method arranges for the to be passed to generate, and the -parameters feature of namespace ensembles takes care of passing that argument along along until it reaches the target method, improbability. Note also that the 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.