Simple Blocks Commentary

General:. Blocks are the code (program) elements of Glee. Blocks are objects containing several members. Among these members is the Glee code. Glee blocks are delimited by curly braces (  {...}  ). Everything between these braces is taken as Glee code. It is to be interpreted and executed. Another member of a Glee block is its local namespace. A block's local namespaces is persistent. This means that when you create and name objects in the block's namespace, they are there the next time you return to the block. This is different than most other languages whose "programs" are stateless. When a block contains a block, a namespace chain is formed. The inner-most block is said to be at scope 0. It's caller is at scope 1. This proceeds all the way to the root block which is the block where all Glee programs start. Named objects in this chain are visible all the way to the root unless shadowed. Shadowing means two objects in the chain have the same name. When Glee looks for named objects, it works up the chain and quits as soon as it finds one. If the scope is less than 2, the block may write to the object. Scopes greater than 1 are read only. If you write an object (at scope greater than 1) with the same name, the higher scoped object is unaffected but becomes shadowed. The concepts of Glee blocks are very rich. I'll start out very simple and slowly expand on the issues. In this tutorial you'll get a view of blocks from 20,000 feet. We'll see them do their thing and only with subsequent block tutorials will we come to know how they do it. But as with other elements of Glee, you really need to know the "how it works" to make good use of the facilities.





Hello World:This is Glee's Hello World program. It requires very little setup. Slap a left brace before the code; a right brace after the code; and it is ready to execute. Just press go.




Monadic Form of Naming a Block: Blocks with no names serve to localize namespaces. But blocks with names also allow the block to be used again and again without redefining it. In Glee, as in other languages, this is the concept of a stored program. Our purpose is to associate the block code with a name and then invoke that code through the associated name. In the monadic form of #PGM, the left argument is a string representing the block's code definition. If this is assigned to a variable as shown here to HW, the block is implicitly given the variable's name. This is a common way of defining Glee programs from external media like files. When blocks are defined and named within an executing program, the dyadic form of #PGM is more commonly used. This is illustrated in the next example. As the examples in this tutorial are stand-alone, we will incorporate the dyadic form of block naming from here on.




Hello World program named HW: For a block to be invoked more than once, it must be put into a namespace. Here I save the block under the name "HW" using Glee's #pgm operator. This is called a named block and is the familiar program object. The #pgm operator assumes the program name on its left and a block on its right. It creates a block object and stores it in the local namespace under the given name. You may be tempted to use the assignment operator by doing something like ({'Hello'}=>p). But when you think about it you realize that Glee invokes the block and returns its result. This is then saved in the variable.




The HW program being called: We can use a program in a Glee expression. When you invoke a program (or call it), it examines its left argument to be a namespace. It then uses this namespace to define objects in its local namespace. The block is executed and passes its result on to the right. If the left argument is not a namespace, the program is executed and the result is stranded with the left argument. Programs don't take right arguments so anything on the right is stranded as well. I use verbose display to illustrate what is really happening.




The HW program with argument: Here I use the field list concepts to deliver an argument to my program. I begin by defining and displaying the program <1>. I can display the members of the named block through it's :ns namespace member <2>. No members exist because the program has not yet been invoked. I call the program supplying its argument [.arg] and verbosely display the stranded result <3>. Now I again display the program namespace showing that the argument arg now exists <4>. Next, I call the program without supplying an argument (no [.arg]) . The verbose display reveals the left argument stranded to the program result (which now uses its persisted arg value) <5>. Correcting the mistake and supplying the left argument namespace correctly solves the problem <6>. Programs copy the contents of the left argument namespace into their namespace when called. So if you supply arguments that are not used by the program, they still get copied into the program's namespace (see xyz)<7> and <8>.I






HW using global variable: I begin this example by clearing the root namespace. My version of HW clears its local namespace this time too (#ns => @;). When the block is invoked this is what happens: 1) The argument namespace is copied into the HW block's local namespace. 2) The block is invoked and the first instruction clears the local namespace. 3) The interpreter tries to find the "arg" variable by first looking in its local namespace. Failing there, it looks up the namespace chain in the call chain. Getting all the way to the root namespace (just one step this time), it still doesn't find it and reports NoValue. Then I create the "arg" variable in the root namespace and do it again. This time, the HW program block still doesn't find "arg" in its local namespace but it does find it in a namespace up the chain ... in the root namespace. Clearing the blocks namespace also clears its arguments. The next example resolves the issue.






HW clearing namespace and preserving arguments: The previous example cleared the namespace and lost the arguments. The #args niladic operator resupplies them as show in this example. Since blocks are persistent and may leave objects around during execution, it is probably a good idea clear the namespace before starting. It is also a good idea to clear it when ending, especially if the program is dealing with large objects like pictures. The next example shows how this can be done.




HW cleaning up namespace at exit: Because the named blocks have state, every object introduced into the block is remembered. It will be there when you return to the block. Sometimes you just want to clean up and return a result. A method (admittedly not elegant) is illustrated here. The last statement arg ' hello world '(#ns => @)->_1}. The output is stranded as before with one more object. The (#ns => @)} clears the namespace and strands in an empty namespace object. The ->_1} drops the last element of the sequence before returning. And <4> demonstrates that the blocks namespace is in fact clear as a result.




:




: