Block Scoping Commentary

General:. Glee stores objects in namespaces by name. Each block in Glee, whether named (e.g. #PGM or #OP) or anonymous, contains a local namespace. A block may call a block which also has a local namespace. Control structures (e.g. :if and :for ) invoke blocks of code which contain namespaces and could invoke other blocks. Glee maintains these namespaces in a chain. It is necessary to allow as much freedom in naming as possible and yet keep different objects with the same name separate. This is called scoping. This tutorial illustrates Glee's method of managing the scope of named objects.

Simple scoping principle and the scope operator (obj * ): This example illustrates simple scoping. The root namespace is cleared and an object "a" is created in it. Using the scope operator (e.g. a* ) Glee returns the scope of the object in that context. As I nest the object in blocks and query its scope, its scope becomes farther and farther away (i.e. a larger number). Local scope is always 0. Scopes then increase as blocks become nested. Parenthesis do not affect scope.

In write scope: I clear the namespace. I create the object 10 => a. I then create a block and show the value of "a" as I change it. Since "a" 's scope is less than 2 (i.e. local or the caller), I can change it. This is the scope most languages provide within the control structures (e.g. for loops). You can see everything outside the block and can change everything in the block's namespace and in the caller's namespace.

Insulating: I illustrate an insulated block here. It is produced using double bracing ( {{ .... }} ). It shows that I can see an outside object, but when I change it, it becomes an inside object. The outside is not affected like it was in the previous example. There is nothing magic here. The rule is an object can be changed if its scope is less than 2. An object is read only (i.e. visible but insulated from change) at scope greater than 1.

Selective exposure: Here you see the technique to achieve general insulation with selective exposure. After opening the first block, I reference "b@" and deliver it (under the same name) as an argument namespace to the inner block b@[.b]. This effectively moves its scope up one level. If I try to reference an object at scope greater than 1, no squak is made ... but no change to its contents is allowed. Note, you are free to rename to match the arguments expected within the block. All blocks up until now have been anonymous blocks. They have no name and they disappear when we are done with them. Thus, while their namespaces are persistent, the blocks are not, so their namespaces disapper when the blocks go away. Glee reference-counts everything, so objects outside the block are not affected (i.e. persist after the block is expunged). Named blocks (e.g. programs and user defined operators) are no different than anonymous blocks except they remain named objects in the namespace. Thus they don't disappear. And equally important, their namespaces are retained. Those contents are available the next time the named block is called. The next tutorial sections describe named blocks.

Experiment: From here on I suggest you experiment. Here I show that going to the third level, I didn't have to rereference "b" because it was still at scope less then 2 when I assigned it. If I went up another level, "b" would have been at scope 2; out of scope; and not changed but rather replicated locally. The rules are simple. Objects seen at scope less than 2 can be changed. Objects at scope less than 2 can be moved to inner scopes without limit through referencing. In referencing, this becomes a reference to a reference to a reference ... with the original object ultimately being affected.