Program (named) Block Commentary

General:.When Glee begins operation, you are already in a block. This is the root block. There you can create and invoke other blocks. Those blocks can create and invoke others. In this context, all the blocks above a block are visible and callable. All variables in those blocks are also visible but they are not assignable. To assign to a variable above a block (i.e. in a caller), the block must be passed a reference to the variable. Glee finds objects given their names. It begins in the most local namespace and continues up the chain until it finds an object with the name it is looking for. If that object is a block, it invokes it. If it is a variable, it uses it in an expression or displays it. If that object is a reference, it can be used as any other variable. Also, when you assign to it, you are assigning to all referents. This section will deal with blocks inside of blocks and some of the object location issues. It will also introduce variable "stickiness", arguments and initilization. All arguments are name oriented rather than positional. There is no caller / callee contract (i.e. signature) in Glee.




Global and argument values: This is the familiar compound interest program. I begin by clearing the namespace and assigning global variables: (#ns=>@;.05=>i;8=>n;). Next I define the compound interest block and name it: ('cmpd'#pgm{'i='i';n='n';f='(1+i^n)';'};). I display the block using :stringv: (Pgm[R2C1:P] Code: {'i='i'; n='n'; f='(1+i^n)';'}). And then I invoke the program with no arguments: (cmpd $;). The result shows that the program sees the global values for "i" and "n". Next I run the program with just the "i" value given as an argument: (.1[.i]cmpd $;) and the result shows that it is now seeing the argument "i" but the global "n" (i=0.1;n=8;f=2.14359;). I run it again argument free. I get the same result as before. This is because the block's namespace retained the value passed by the argument in the previous run. I change the global "n" and run it niladically to show it still sees the global value for "n" but the local value for "i". I run it again with a different argument "i" (i=0.1; n=4; f=1.4641;). This illustrates the visibility of variables outside the block. It illustrates the passing of arguments into the block. It illustrates the "stickiness" of variables within the block. And in general it illustrates poor style. As a rule, you don't want your programs to find their variables outside the block. You want your programs to create their own variables as functions of variables passed as arguments.




Default values and reloading arguments (using #ARGS): One way to give a program default behavior is to initialize variables and then overwrite them with data passed as arguments. This example illustrates the technique. First I assign the variables (10=>n;.07=>i; ). But this isn't what the program does first. The program first loads the arguments into its namespace. Assignment of these same variables then replaces the argument values. If no arguments are given this presents no problem. But if you give arguments, they immediately get clobbered. The #args operator reloads them. You can do this anywhere and any time in your programs. This technique removes the "stickiness" characteristics of the arguments. If arguments are not given, the defaults always take their place.




Initialization (#IX) and execution: For those cases where we want initialization and then we want the program to have an adaptive state, the #IX operator is used. #IX is followed by a block definition { ... }. #IX just runs the code in the block at scope one higher than itself. Typically, this will be scope 0 of the program. It then sets a switch so every time it is incurred in the program after that, it is ignored. The effect is to have a way of creating helping functions and doing other initializations when the program is created.




Initialization (#IX) and immediate return: For those cases where you want initialization only, add the return (: return or GLEEphicly :<- ) to exit the program after initialization.




Interest formulas: This is the familiar suite of interest formulas: SPCA: Single Payment Compound Amount; SPPW: Single Payment Present Worth; USCA: Uniform Series Compound Amount; SFP: Sinking Fund Payment; CR: Capital Recovery; and USPW: Uniform Series Present Worth. I implement them all off of the base SPCA block. I give this block an initial expression that all the others use. In some cases I must reference the interest rate "i" for independent use. To do this I use the "spca:ns" namespace reference with the field ".i" (spca:ns.i). The Glee interpreter uses long right scope to resolve this compound reference. It does not invoke "spca" here. Rather, it is simply addressing it as an object with state. I initialize the spca namespace by running once which just invokes the #ix block and exits. You may also notice I used "spca" as if it were just another variable. In these cases, it is being invoked. It is its result that I am using. The Glee interpreter is a pretty sophisticated collection of state machines. It recognizes at run-time that the "spca" left argument is not a namespace and so does not use or compromise that argument. It just executes using data in its own namespace or global objects it finds in the chain. This makes the coding very natural and free of unnecessary parenthesizing.




Local Programs and Loading Arguments: This example is just a little different twist of the preceeding example. Instead of having several programs in the global namespace, I have a single program named "AllInt". This program has two local programs: "fmt": ('fmt' #pgm{ 'i='i'; n='n'; 'fn'='r'.'$};) does the formatting. "ci": ('ci' #pgm{1+i^n};) is the compound interest calculation used by the expressions for the various interest calculations. Here again I use the "#args" operator. In the first example, I used it in the initial expression. Here, I use it in the main AllInt program. Any time this special operator is invoked, it reloads the arguments into the local namespace. In this example, I run it after I set the defaults (#ns=>@; .08=>i; 10=>n; 'ci'=>fn;). The effect is the same as the use by the initial expression and the strategy is the same. This technique is a little cleaner and it obviates an effort of the caller to set the initial expression. If the caller sets the initial expression, it does get run. However, his efforts are trumped with the clearing of the local namespace (#ns=>@;) followed by code to set the default values. Try running this with the comments checkbox selected. It will highlight the operations. Notice when I called with arguments I made sure the "n" value was a sequence using the enclose (>) operator (9..11>). If I hadn't done this, it would have taken the "9" for "n", the "10" for "i" and would have ignored the remaining data.




: