General:. Namespaces are where
Glee keeps track of symbolic names (e.g. variable names and
program names). They are implemented in sequences with provisions to prevent
duplicate names. Glee ignores case when referencing elements of a
namespace. Valid Glee names begin with an alphabetic, contain no
symbols, and contain no embedded whitespace. They are not case sensitive but
namespaces retain case in names for better readability. They may be of any
length. Valid characters for Glee names are ( "a
thru z; A thru Z; 0 thru 9; and _ ).
Any time you make an assignment in Glee (e.g. (10=>i)) an entry is made in the namespace. If the object "named" already exists, it is removed from the namespace. The new symbol and object are then "put" into the namespace. Namespaces are objects just like the objects they hold. Namespaces can be passed as arguments to operators and programs (if they support the namespace context). Below are some examples to help you get familiar with the behavior and use of namespaces.
Note: These examples assume a clear namespace unless comments and examples suggest otherwise. In most cases they create the clear namespace with operations like .clear => @ or #ns => @.
Glee namespaces reside in Glee blocks. When
blocks are nested, their namespaces form a chain all the way back to the root
block. Assignments are always made to the two nearest namespaces in the chain.
This is the local namespace and the namespace of the calling block. The calling
block is tested first. If the name exists there, assignment causes its contents
to be changed. Otherwise, the name is created and retained in the local
namespace. With references, these assignments can affect objects in other
namespaces. This panel illustrates saving objects (variables) into the most
local namespace (in this case the root) and then viewing the most local
namespace. The indexing operator ( [ ] ) with no left argument is
taken by Glee as a request to "index into" the most
local namespace (in this example, root).
Adding a namespace and populating
it:First I (#ns =>@) to clear the namespace. This example
assigns 101 to "i" in the local namespace. Using
the niladic operator (#NS) it creates a clean namespace and saves it
as "n" in the local namespace. Four objects are then added
to the "n" namespace named
"num". The two objects stored into "str"
and "num" can be indexed-in in a single operation
because their referrants form a sequence (heterogeneous mixing ... in this case
a number and a string ... cause a sequence to be formed). Now let's see what we
have: The indexing operator (  ) with no left argument causes the
most local namespace to result. This has the same effect as pressing the NS
button. The object names ( "i " and "n" )
are displayed. To see what is in the namespace "n", we index
into it with an empty index (n). The display shows the type and
number of elements in each object.
Namespace (ways of
indexing): Starting with a clear local namespace, we create a namespace
object "n" and introduce an object "j"
into it. We then display the local namespace () and see it contains
the namespace named "n". The contents of the namespace
n, (found by n which is the same as just referencing it
"n") are then displayed. We can also reference n by
indexing into the local namespace with a field ([.n]). And we can
index into n in the same way (n[.j]) to reference j.
But notice, indexing always yields a result of the same type as what is being
indexed. So to reference the actual object, we have to disclose it with
the (<) operator. Because the indexing operation could return
several objects, the disclose operator must return a sequence. Thus, to
actually obtain the object, we just disclose the resulting sequence as well
with (n['j']< <). Obviously, albeit consistent, this is a major
hassle. The next example shows us the way out.
Namespace references: As noted
in the previous example, a simpler way of accessing namespace objects is
needed. The answer is references. Reference objects are created with the
(@) reference operator. Applied to any object, it creates a
reference to that object. One important characteristic of references,
especially concerning namespaces, is allowing "addressing" of their
items with "fields".
This example begins by #ns =>@ clearing the local namespace. In #ns @ =>rn, the #ns creates a namespace and @ creates an anonymous (no name associated) reference to it which is saved as "rn" in the local namespace. 10=>rn.j creates an item named "j" in the "rn" namespace. "j" then references the numeric object containing the value 10. Notice, the the use of a field (".j") for indexing through the reference to the namespace.
With an empty left argument, ( @ =>rl ) you can create a reference to the local namespace and save this reference. Here I save it by name "rl". Now having this reference I can use the notation ( rl.rn ). This uses the field " .rn " to index the reference "rl" yielding the contents of "rn" from the local namespace.
I can now obtain the value for "j" with ( rn.j ). And, since "rn" resides in the namespace referenced by "rl" I can see "j" with (rl.rn.j). In both cases, I see the value which "j" holds being 10. In a round-about way I have achieved a popular hierarchical form of referencing without breaking the simple Glee model.
Namespaces can be managed under program control. Here I populate the local
namespace with three objects ("i","s", and
"q"). The local namespace is displayed ( returns the
local namespace and with nowhere to go, it displays its contents). Next, I
remove the "s" object with the familiar without (
~ ) operator. The resulting namespace without the
"s" object results. Its contents of names displays. Now
again displaying the local namespace you see that the "s"
object is still there. This is because I didn't save the result.
I correct this with the next example (~ (.s) =>$;). Notice, this is just the familiar indexed assignment. With a NULL right argument, I implicitly assign into the local namespace. Thus, programs can control the contents of namespaces (and yes, if not done properly, subsequent code execution can have difficulty).
Now, using anonymous references I remove "i" using the without field notation and assigning back to the anonymous reference to the local namespace (^@ dereferences the result so I can display its referant). Finally I do the same with "q" and have now cleared the namespace.
Namespace assign: This
example illustrates a number of ways you can create objects in namespaces and
assign into them. All of these examples are directed to the local namespace.
Namespace recursion: This
example shows a problem you can create for yourself ... sometimes quite
innocently. Namespaces can contain namespaces. As such, you can create a loop
condition that confuses Glee. Starting with a clear local
namespace, I create two namespaces ( #ns=>a;#ns=>b;). I then
have them store each other (b=>[.nsb]a; a=>[.nsa]b;). In
non-verbose mode they can easily display their contents because the display is
not recursive to depth (a $; b $; a[.nsb]< $;) yielding
(nsb; nsa; and nsa) as expected. But if we try to see the
size of a namespace with (a.size $;) which is
recursive,Glee chases its tail. Sizing "a" it
needs the size of "b". Sizing "b" it
needs the size of "a" which needs the size of
"b"... tilt! Glee has a crude check for this
and responds with (a.size ^Value Recursion
Error: C:\CPPPROJS \Interpreter \KNS.cpp). It's better
than a hang but not much. Right now Glee can recover but it is
not smart enough to clean up its mess ... it leaks. So first, avoid this
problem. And second, if you have this problem, fix it immediately and reload
Glee to reclaim the leaked memory.
References and namespaces:
References refer to data objects. These objects may be namespaces. When
Glee creates references, it creates intermediate namespaces as
needed. Glee namespaces and compound references work hand in hand
to give structure or record capability. In this example I start
with a clean namespace. I create two compound references (p.q.n)
refering to a numeric object; and (p.q.s) referring to a string
object. When the "n" variable was created, the
"p" and "q" namespace references didn't
exist. "p" was created as a reference to the most local
namespace. "q" was created as a reference within
"p". When it came time to create "s", all
the intermediate objects already existed. Thus it became a relatively simple
variable assignment. The remainder of the example illustrates various views of
Fieldlists and namespaces:
This is going to be a little tricky so watch carefully. I begin with a clean
namespace and create two objects, "i" and
"s". When I collect fields (they are special name
objects beginning with a period ".") within indexing
brackets ([.i.s]) I form a fieldlist. Fieldlists are indexing objects.
In this case one is operating on its non-existent left argument. The most local
namespace is assumed. Indexing into a namespace with a field list returns a new
namespace containing the addressed objects. If we compound this as in the
example ( [.i.s][.ii.ss]), we have name substitution in the resulting
namespace. What was "i" is now "ii" and
what was "s" is now "ss". The new
namespace names copies of objects from the source namespace. I save this new
namespace as a reference ( [.i.s][.ii.ss]@ =>arg ^@$;) and reveal
its contents. I call it "arg" for argument because
this illustrates how Glee passes arguments to named blocks
called programs. Using "arg" I can now reference the
data objects "ii" and "ss". Finally I
assign to "ii" and illustrate it changing without changing
"i". This is because they are two separate objects.
Fieldlists and references:
The previous example gave us a taste of how we might create arguments of
copies. This example shows how we can create arguments of references. I begin
with a clean namespace and the same two objects as the previous example. This
time, instead of creating copies of both objects in a new namespace under new
names, one of the new objects, "ii" is a reference to
its source object "i". As such, changes to
"i" affect "ii" and vice-versa. This
referencing is accomplished with the semantics ((i@)) in the
instruction ((i@)(s)[.ii.ss]@ =>arg $;). While it is common to
speak of other languages in terms of their semantics I am hesitant to do
that with Glee. Glee is really a language of
operations working from left to right. It has very few semantic rules. This
makes it easy to learn and unambiguous to understand. But it does require that
you start thinking in terms of operations and results. The concepts presented
here are crucial to using blocks and control structures. They are
the mechanism for argument passing.
Creating arguments with
namespaces:As you will see with blocks, namespaces are crucial
communication objects in programs. This example shows the behavior of relating
data to names in namespaces. To simplify argument passing, Glee
makes data conform with fieldlists. If there are more fields than data objects,
Glee left takes the data object to conform. If the object is
numeric and there is more than one field, the elements of the numeric are
assigned to the fields. For a sequence with one field, the field gets the whole
sequence. For a sequence and more than one field, the fields get correspending
elements of the sequence. Left take is used to force conformity.
Namespaces without field
list: Before leaving namespaces, look at how we can use field lists to
manage the contents of them. I start with three objects,
"i", "j", and "k". I
show them in the namespace. I then use the without operator and a
field list to act on a reference to the most local namespace
(@~(.i.k)). This returns a reference to a new namespace without the
variables in the field list. I can then assign this to the most local namespace
reference and I have deleted those objects from the namespace
(@~(.i.k)=>@ ^@). (Note: the ^@ reveals the
contents). The objects don't go away until I reassign the namespace. Since
namespaces are just sequences of pointers, this is all very efficient. Notice
how in Glee, once you get the feel for objects and operators, you
can accomplish just about anything without having to learn lots of special
rules. Glee is easy to learn and use in spite of its richness and