Namespaces Commentary

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 => @.

Root Namespace: 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 "i","j","str", and "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.

Namespace (without): 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[251]). 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 the results.

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][]), 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][]@ =>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)[]@ =>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 power.