New Release 83

General:. This page generally describes new functionality in the 83 series of revisions and uploads. This is Working Documentation that with maturity will be moved to the Master Documentation.

Most of the time has been spent revisiting blocks, control structures, compound variables, and references. My main issue has been dealing better with scope and namespaces. I was having extreme difficulty doing conventional scoping (i.e. blocks create new scopes unless they are in control structures). I'm now experimenting with an alternative. Beginning now, if an object is scope 0 (local) or scope 1 (caller), the object can be changed. This makes blocks look like they have no scoping (i.e. objects in the caller can be redily changed). However, if you put a block within a block, you get scoped insulation since you're now dealing with the caller of the caller (i.e. scope is 2 and thus read only).

While at first I felt this was a cop-out, I think I like it. By double blocking (e.g. {{ code here }} ) I get read only insulation. If I want to work free and loose and am just looking for a little modularity, I can single block (e.g. { code here } ) and caller objects look local to the block. This will be particularly useful with user defined operators and named blocks (programs). When named blocks are defined within named blocks I can relax their scoping as if they were in-line coding, yet I still have modularity ... kind of like a macro. This is natural for unnamed (anonomous) blocks common to control structures. For example, in an if control structure (e.g. :?(a=b){t+a=>t;'a=b'}::{'a~=b'} ) I want to be able to see the caller's values for a, b, and t, and I want to be able to change them.

If I want more insulation, I can double block. Then, to make changes to caller objects I must pass them into the block's namespace as references.

Caution: This change will break existing programs.

Double Block Scoping: <1> Scope of i is 0 (as reported by the monadic scoping operator i*) and its value is 10. I enter a double block {{ ... }}. Each block moves me one away from the scope of i. A single block is formed by { ... }. Entering a block raises scope by 1. Since I've moved into a double block (i.e. {{ ... }} ), I have moved two scopes away from i. <2> I can still see i but it's scope is now 2. <3> When I assign to i, its scope being greater than 1, I create a copy for the result yielding a new i at scope 0. <4> Leaving the double block, I see that the original i has not been changed. Thus, entering a double block can be said to insulate caller objects from assignment. Within a double block, they are out of scope because their scope is greater than1.

Single Block Scoping: This example is nearly identical to the previous example. The only difference is the blocking. In this case, I've single blocked rather than double blocked. Within the block, i is seen to be scope 1 and can be changed. Notice how i remains at scope 1 with this change. And notice when we leave the block, i is in fact changed.

Reference passing into double block: The only way to reduce scope while entering into blocks is to use a reference. As this example shows, a reference to i is passed into the first block. It maintains it's scope=0. Entering the second block, it's scope is 1 and is thus still assignable. If we endered a third block, it's scope would have been 2 and no longer assignable. However, we could have passed the argument into the next block in the same fashion and maintained scope 0 (as deep as we wanted to continue the practice). Notice that i is indeed a reference. It's referencing characteristics cannot be removed by assignment because what is assigned goes to the referent. A reference symbol can be reclaimed by deleting it (e.g. @ ~.i=> @) and then reassigning it.