Current issue

Vol.26 No.4

Vol.26 No.4

Volumes

© 1984-2024
British APL Association
All rights reserved.

Archive articles posted online on request: ask the archivist.

archive/18/3

Volume 18, No.3

This article might contain pre-Unicode character-mapped APL code.
See here for details.

Ghost Variables

by Ray Cannon

As I was going up the stairs,
I met a man, who was not there,
He was not there again today,
I do wish he would go away.

How to emulate “Persistent Local Variables” in Dyalog APL/W.

Stephen Taylor’s article on “Persistent Local Variables”, and recent exchanges in the “DFNS discussion group” have prompted me into writing these notes.

In APL, every time a function is called, any LOCAL variable defined within the function needs to be assigned before it can be used. That is on subsequent calls, the function retains no memory of its local variables’ previous values. Outside the function, these local variables have no presence.

However, if the function refers to a GLOBAL variable, once initially assigned, no further assignments are required, and values are maintained between calls. Outside the function, these global variables do have a presence, and can be “molested”.

It would be very useful if we could define a third type of variable, which although local to the function (i.e. have no presence outside the function) could retain their value between calls. This is what is meant by the term “Persistent Local Variable”.

As way of an example consider the dynamic function Next:

Next„{
     ¾»'':¸.next„¾      © Assign a new starting value
     ¸{¸.next}¸.next+„1 © Return incremented value
 }

When called, its left argument is a reference to a namespace, in which it stores its GLOBAL variable “next”. Its right hand argument may be either a numeric which it uses to initialise itself, or the empty text vector '', in which case, it increments the value of the global variable, and returns that value as its result.

                    ŒSE  Next 0
                    ŒSE  Next ''
1
                    ŒSE  Next ''
2

Note that the global variable “next” is located in the quadSE namespace:

                    ŒSE.Œnl 2
next
                    ŒSE.next
2  

Now Dyalog APL allows one to assign functions and derived functions. So I can “glue” the quadSE namespace onto the Next function, and call it NextOne:

                 NextOne„(Œse)°Next
                 NextOne 10
                 NextOne ''
11
                 NextOne ''
12

But this is still using the same global variable

                 ŒSE.next
12  

However, if instead of using an existing NAMED namespace, I create an UNNAMED namespace

                 NextTo„(ŒNS'')°Next
                 NextTo 50
                 NextTo ''
51
                 NextTo ''
52

The global variable next exists in an UN-NAMED namespace to which I have NO access except via the derived function NextTo.

Note that if I create another Un-Named namespace “It” does not effect the first UN-NAMED namespace:

                 NextFree„(ŒNS'')°Next
                 NextFree ¯50
                 NextFree ''
¯49
                 NextFree ''
¯48
                 NextTo ''
53
                 NextOne ''
3

So there we have it, outside the function, a variable that has no presence, but whose value persists from one call to the next.

NextTo and NextFree both have their own separate copy of a “GLOBAL” (but invisible) variable called #.[Namespace].next. One could describe them as functions “HAUNTED” by their “GHOST” variables.

Since these GHOST variables are really GLOBAL, one should be able to share them between two functions. (In FORTRAN I think this is described as COMMON data.)

Well, since “Real programmers can write FORTRAN in any language”….

Operator “attach” should do the trick:

a(aa attach ww)w
 –(1œa),'„w°aa'
 –(2œa),'„w°ww'
'PUT' 'GET'( {¸.data„¾}   attach   {¸.data}) ŒNS'' 

This creates functions Put and a which share the same COMMON but private variable #.[Namespace].data

       Put 1 2 3
       Get''
1 2 3
       Put 'Hello Sprite World'
       Get ''
'Hello Sprite World'

script began 22:49:29
caching off
debug mode off
cache time 3600 sec
indmtime not found in cache
cached index is fresh
recompiling index.xml
index compiled in 0.1832 secs
read index
read issues/index.xml
identified 26 volumes, 101 issues
array (
  'id' => '10002020',
)
regenerated static HTML
article source is 'HTML'
source file encoding is ''
read as 'Windows-1252'
completed in 0.2053 secs