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.