Technical Bulletin - GT.M Alias Variables

Copyright © 2010 Fidelity Information Services, Inc.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts and no Back-Cover Texts.

GT.M™ is a trademark of Fidelity Information Services, Inc.  Other trademarks are the property of their respective owners.


This document contains a description of GT.M and the operating instructions pertaining to the various functions that comprise the system.  This document does not contain any commitment made by FIS.  FIS believes the information in this publication is accurate as of its publication date; such information is subject to change without notice.  FIS is not responsible for any errors or defects.


Revision History

Version
Date
Summary
1.0
July 15, 2009
First published version

GT.M Group

Fidelity National Information Services, Inc.

2 West Liberty Boulevard, Suite 300

Malvern, Pennsylvania 19355

United States of America

GT.M Support for customers: +1 (610) 578-4226 / gtmsupport@fisglobal.com


Switchboard: +1 (610) 296-8877

Website: http://fis-gtm.com



Table of Contents

 
  1. Technical Bulletin - GT.M Alias Variables
    1. Revision History
    2. Table of Contents
    3. Overview
    4. Alias Variables
    5. Alias Container Variables
    6. SET *
    7. KILL *
    8. Performance
    9. ZWRITE / ZSHOW "V"
    10. NEW
      1. Exclusive NEW
    11. Pass-by-reference
    12. Transaction Processing
    13. $ZAHandle()
    14. $ZDATA()
    15. View
    16. $View()
    17. Annotated Extended Alias Example


Overview

Effective V5.3-004, GT.M adds support for alias variables and alias container variables.


Alias variables provide a layer of abstraction between the name of a local variable and an array analogous to that provided by M pass by reference in subprogram invocations (with a DO command or a function call).  Multiple local variables can be aliases to the same array, and a SET or KILL to one acts as a SET or KILL to all.  Alias container variables provide a way of associating a reference to an entire local variable array with a data-cell, which protects the associated array even when it’s not accessible through any current local variable name.


GT.M aliases are intended to provide low level facilities on which an application can implement object-oriented techniques.  An object can be mapped onto, and stored and manipulated in an array, then saved in an alias container variable whence it can be retrieved for processing.  The use of appropriate subscripts in the array used for a container, provides a way to organize the stored objects and retrieve them by using the $Order() function to traverse the container array.  The use of alias variables to implement objects provides significant efficiencies over traditional local variables because alias variables and alias container variables eliminate the need to execute MERGE commands to move objects.


New SET * and KILL * commands manipulate alias variables and alias container variables.


Within this document:



Alias Variables

Alias Variables provide access to an array through multiple names.  Conceptually an alias variable is the same as a pass-by-reference joining of multiple variable names, except that the joining of alias variables is explicit, whereas that of variables passed by reference is implicit.  Indeed, the underlying implementation of alias variables and pass-by-reference within GT.M is the same.  For example:

GTM>Kill A,B

GTM>Set A=1,*B=A ; B & A are aliases

GTM>Write B
1
GTM>

Alias Container Variables

Alias container variables are (subscripted) lvns protecting arrays for subsequent access by an alias variable.  Since accessing an array requires an name, you can alias a name with the alias container to regain access to an array stored in a container.  For example:

GTM>Kill A,B,C

GTM>Set A=1,*C(2)=A ; C(2) is a container

GTM>ZWRite
A=1 ;*
*C(2)=A

GTM>Set *B=C(2) ; B is now an alias

GTM>Write B,":",$Length(C(2)),":" ; An alias variable provides access but a container doesn't
1:0:
GTM>

SET *

S[ET][:tvexpr] *lvn|name1=name2[,...]


A SET * command explicitly creates an alias.  Any previous array associated with lvn or name1 ceases to be associated with it, and if lvn was the only lvn or name associated with that (old) array in any scope, GT.M may reclaim the space it occupied.  Alias assignment does not require that any data set exist for name2; the assignment simply creates an association.



GT.M maintains a count of the number of aliases associated with an array (the array associated with a traditional local variable, sans any aliases, is one).  When the count drops to zero, space used by that array can be reclaimed by the GT.M garbage collector.

It is possible to create an association between two names, neither of which has any value.  Assigning a value to one makes the values visible, e.g.:

GTM>ZWRite ; Nothing there

GTM>Set *A=B ; Create an association

GTM>ZWRite ; Still no data to look at

GTM>Set A("Malvern")="Pennsylvania" ; Create a node

GTM>ZWRite ; Now both have values
A("Malvern")="Pennsylvania"
*B=A

GTM>

Creating an alias container variable not only creates the association but also assigns data (the empty string) to the alias container node:

GTM>ZWRite ; Nothing there

GTM>Set *C("I am a container")=D

GTM>ZWRite ; Both array for C and association for C("I am a container") are visible
*C("I am a container")=D

GTM>Set D=4,D("Jacksonville")="Florida" ; The array for D comes into existence

GTM>ZWRite ; All is revealed
*C("I am a container")=D
D=4 ;*
D("Jacksonville")="Florida"

GTM>

Attempting to create an alias from subscripted lvn that is not an alias container variable triggers an error.  Continuing the last example:

GTM>Set *E=C("I am a container") ; This works because C("I am a container") is a container
GTM>Set *F=C(4) ; But this fails because C(4) is not a container
%GTM-E-UNDEF, Undefined local variable: C(4)

GTM>ZWRite E,F ; Note that E has the value originally assigned to D but F remains undefined
E=4 ;*
E("Jacksonville")="Florida"
%GTM-E-UNDEF, Undefined local variable: F

GTM>

KILL *

K[ILL][:tvexpr] *lvn|name[,...]

KILL * removes the association between its arguments, and any associated arrays.  The arguments are left undefined, just as with a standard KILL.  If the array has no remaining associations after the KILL *, GT.M can reuse the memory it occupied.  For example:

GTM>Set A=1,*B=A ; Create an array and an association

GTM>ZWRite ; Show that the array and association exist
A=1 ;*
*B=A

GTM>Kill *A ; Remove the association for A - it now has no association and no array

GTM>ZWRite ; B is a traditional local variable
B=1

GTM>Set A=2 ; Create an array for A

GTM>ZWRite ; A and B have different values and both are traditional local variables
A=2
B=1

GTM>

KILL on the other hand, removes data in the array (and possibly the array itself) without affecting any alias association.

GTM>Set A=2,*B=A ; Create an array and an association

GTM>ZWRite ; Both array and association exist
A=2 ;*
*B=A

GTM>Kill A ; Kill the array

GTM>ZWRite ; There's no data to show

GTM>Set B=3 ; Create a new array by setting a value

GTM>ZWRite ; The association was unaffected by the Kill
A=3 ;*
*B=A

GTM>

KILL * of a container variable is just like a KILL of an alias variable, and deletes the association between lvn and array.

KILL * treats an alias formed though pass-by-reference the same as any alias variable by removing the alias association:

$ mumps -run killalias
killalias    ; Demonstrate Kill * of pass by reference
    ZPrint ; Print this program
    Set A=1,C=3
    Write "------------",!
    Write "Initial Values:",!
    ZWRite
    Do K1(.A,.C)    ; Pass A & C by reference
    Write "------------",!
    Write "Value of A is unchanged because of Kill *B, but C has changed: ",!
    ZWRite
    Quit
    ;
K1(B,D)        ; A & C are bound to B & D respectively
    Write "------------",!
    Write "A & B are aliases, as are C & D:",!
    ZWRite
    Kill *B
    Set B=2,D=4
    Write "------------",!
    Write "After Kill *B, A & B are different but C & D remain associated:",!
    ZWrite
    Quit
------------
Initial Values:
A=1
C=3
------------
A & B are aliases, as are C & D:
A=1 ;*
*B=A
C=3 ;*
*D=C
------------
After Kill *B, A & B are different but C & D remain associated:
A=1
B=2
C=4 ;*
*D=C
------------
Value of A is unchanged because of Kill *B, but C has changed:
A=1
C=4
$

Performance

With two exceptions, alias and alias container variables add no overhead to normal local variable performance:


There is no reason to avoid aliases in any situation, but in those two contexts, attention to tidy design will be rewarded.

GT.M uses garbage collection to manage the storage used for local variables.  Increasing the use of local variables, for example, to implement objects, will increase the need for gargage collection, even though the garbage collector and storage management are designed to be light weight and self-tuning.  The use of alias variables to implement objects, however, is as efficient as any other method is likely to be, and except for the normal admonition to not keep arrays and local variables around when they are not needed, and to not create levels of contexts over and above those actually needed by appliation logic, you can use alias variables as liberally as your application needs demand.

ZWRITE / ZSHOW "V"

ZWRITE as applied to local variables and ZSHOW "V" are conceptually similar, with two differences:


As tool for debugging, and to capture process state, ZWRITE and ZSHOW "V" graphically document alias variables, alias container variables, and the associated data as described below, in what is called the "ZWRITE format."

In the ZWRITE format, the contents of an array are displayed with the name associated with that array that appears first in the lexical ordering of names.  GT.M displays both the unsubscripted and subscripted nodes and values, appending a notational space-semicolon-asterisk (";*") sequence to the unsubscripted value, if any.  The ZWRITE format output is designed to be read into a GT.M process with the commands Read x and Set @x (where x is any name) executed in a loop.  ";*" acts as a comment ignored by the SET command.  In the following example, since A and C are aliases associated with the same array, the nodes of that array are output with A, which occurs lexically before C, even though the values were assigned to C:

GTM>Set C=1,C("Malvern")="Wales",*A=C,*B(-3.14)=C

GTM>ZSHow "V" ; ZWRite would produce the same output
A=1 ;*
A("Malvern")="Wales"
*B(-3.14)=A
*C=A

GTM>ZWRite C ; Only one is name associated with the array on this ZWRite command
C=1 ;*
C("Malvern")="Wales"

GTM>

Continuing the example, if the variables selected for the ZWRITE command do not include any of the the associated alias variables, the output shows only the reference, not the data:

GTM>ZWRITE B ; B only has a container
*B(-3.14)=A

GTM>

When ZWRITE / ZSHOW "V" encounters an alias container for an array with no current alias variable, it uses a name $ZWRTACn as the made-up name of an alias variable for that array, where n is an arbitrary but unique integer.  The SET command recognizes this special name, thus enabling the output of a ZWRITE / ZSHOW "V" to be used to recreate alias containers without associated alias variables.  Continuing the example above:

GTM>Kill *A,*C ; Delete alias variables and associations, leaving only the container

GTM>ZWRite
$ZWRTAC=""
*B(-3.14)=$ZWRTAC1
$ZWRTAC1=3 ;*
$ZWRTAC1("Malvern")="Wales"
$ZWRTAC=""

GTM>

ZWRITE produces $ZWRTACn names to serve as data cell anchors which SET @ accepts as valid set left targets.  $ZWRTACn names are created and destroyed when using ZWRITE output to drive restoration of a previously captured variable state.  Except for their appearance in ZWRITE output and as left-hand side SET @ targets, they have no function.  Other than SET, no other commands can use $ZWRTAC* in their syntax.  Although $ZWRTACn superficially looks like an intrinsic special variable (ISV), they are not ISVs.  $ZWRTACn with no subscripts can serve as the target (left side of the equals-sign) of a SET * command.  SET $ZWRTAC (no trailing integer) deletes all data cell associations with the $ZWRTAC prefixed aliases. GT.M only recognizes the upper-case unabbreviated name and prefix $ZWRTAC.


NEW

For the scope of the NEW, a NEW of a name suspends its alias association.  The association is restored when the scope of the New ends.  The array remains in existence - it can be modified through other alias variables with which it is associated and which remain in scope.  If none of its alias variables is in scope, the array remains intact and again becomes visible when the scope is restored.  For example:


$ mumps -run stackalias
stackalias    ; Demonstrate New with alias
    ZPrint ; Print this program
    Set A=1,*B=A,*C(2)=A ; Create some aliases
    Write "------------",!
    Write "ZWRite in the caller before subprogram",!
    ZWRite
    Do S1    ; Call a subprogram
    Write "------------",!
    Write "ZWRite in the caller after subprogram - A association is restored",!
    ZWRite
    Quit
    ;
S1        ; Subprogram
    New A
    Set A="I am not an alias",B="I am an alias"
    Write "------------",!
    Write "ZWRite in the subprogram with new A and modified B",!
    ZWRite
    Quit   
------------
ZWRite in the caller before subprogram
A=1 ;*
*B=A
*C(2)=A
------------
ZWRite in the subprogram with new A and modified B
A="I am not an alias"
B="I am an alias" ;*
*C(2)=B
------------
ZWRite in the caller after subprogram - A association is restored
A="I am an alias" ;*
*B=A
*C(2)=A
$

Exclusive NEW

An exclusive New can create a scope in which only one association between a name or an lvn and an array may be visible.  In this case, ZWRITE nevertheless shows the existence of an alias, even when that array is accessible from only one name or lvn.  The following is essentially the same as the prior example but using an exclusive NEW:

$ mumps -run stackalias1
stackalias1    ; Demonstrate New with alias
    ZPrint ; Print this program
    Set A=1,*B=A,*C(2)=A ; Create some aliases
    Write "------------",!
    Write "ZWRite in the caller before subprogram",!
    ZWRite
    Do S1    ; Call a subprogram
    Write "------------",!
    Write "ZWRite in the caller after subprogram - A association is restored",!
    ZWRite
    Quit
    ;
S1        ; Subprogram
    New (B)
    Set A="I am not an alias",B="I am an alias"
    Write "------------",!
    Write "ZWRite in the subprogram - Notice B is flagged as an alias",!
    ZWRite
    Quit
------------
ZWRite in the caller before subprogram
A=1 ;*
*B=A
*C(2)=A
------------
ZWRite in the subprogram - Notice B is flagged as an alias
A="I am not an alias"
B="I am an alias" ;*
------------
ZWRite in the caller after subprogram - A association is restored
A="I am an alias" ;*
*B=A
*C(2)=A
$

The GT.M implementation of aliases and of exclusive NEW interact in a way making exclusive NEW slightly asymmetric to non-exclusive NEW.  As a consequence of the expectation exclusive NEW tends to restrict the scope of more variables than it's preserving, when GT.M encounters an exclusive NEW it creates a fresh data environment and effectively aliases the excluded variables with their original copies.  This technique tends to improve performance and meets the M standard.  However, it has two implications: if there are no other alias associations beyond that created by the exclusive NEW, a KILL * with no arguments has the same effect as a KILL with no arguments, and ZWRITE and $ZDATA() treat an exclusively NEW variable as an alias - note the ZWRITE output in the immediately preceding example.

Pass-by-reference

GT.M's underlying implementation of pass-by-reference and alias variables is the same. As illustrated by the program killalias above, ZWRITE displays variables joined though pass-by-reference using alias conventions.  Pass-by-reference is distinguished from aliase variables by its implicit creation and elimination.

Note the interaction between pass by reference and alias variables if you attempt to change the association of a formallist parameter in a subprogram:

$ mumps -run switchalias
switchalias    ; Demonstrate Set * on formalist parameter
    ZPrint    ; Print this program
    Set A=1,B=2
    Write "------------",!
    Write "Initial Values:",!
    ZWRite
    Do S1(.A)
    Write "------------",!
    Write "On return:",!
    ZWRite
    Quit
    ;
S1(X)    ;
    Set X=3
    Write "------------",!
    Write "Inside call - note alias association for formallist parameter:",!
    ZWRite
    Set *X=B,X=4    ; Change association of formallist parameter
    Write "------------",!
    Write "Note changed association",!
    ZWRite
    Quit
------------
Initial Values:
A=1
B=2
------------
Inside call - note alias association for formallist parameter:
A=3 ;*
B=2
*X=A
------------
Note changed association
A=3
B=4 ;*
*X=B
------------
On return:
A=3
B=4
$

Transaction Processing

The TSTART command can optionally list names whose arrays are restored on a transaction RESTART.  If any of these are alias variables or have nodes which are alias container variables, their associations are also restored on transaction RESTART:

$ mumps -run tprestart
tprestart    ; Transaction restart variable association also restored on restart
    ZPrint    ; Print this program
    Set A="Malvern",C="Pennsylvania",E="USA"
    Set *B=C,*D(19355)=E
    Write "------------",!
    Write "Initial values & association",!
    ZWRite
    TStart (B,D) ; On restart: A not restored, B,D restored, C,E restored by association
    If '$TRestart Do ; Change C,E if first time through
    .Set C="Wales",E="UK"
    .Kill *D(19355)
    .Write "------------",!
    .Write "First time through transaction; B,C,D,E changed",!
    .ZWRite
    .Set A="Brynmawr"
    .Kill *B
    .Write "------------",!
    .Write "A changed; association between B & C and D & E killed; B,D have no value",!
    .ZWRite
    .TRestart
    Else  Do ; Show restored values on restart
    Write "------------",!
    Write "Second time through transaction; B,C,D,E & association restored",!
    ZWRite
    TCommit ; No global updates in this transaction!
    Quit
------------
Initial values & association
A="Malvern"
B="Pennsylvania" ;*
*C=B
*D(19355)=E
E="USA" ;*
------------
First time through transaction; B,C,D,E changed
A="Malvern"
B="Wales" ;*
*C=B
E="UK" ;*
------------
A changed; association between B & C and D & E killed; B,D have no value
A="Brynmawr"
C="Wales" ;*
E="UK" ;*
------------
Second time through transaction; B,C,D,E & association restored
A="Brynmawr"
B="Pennsylvania" ;*
*C=B
*D(19355)=E
E="USA" ;*
$

Note that TROLLBACK does not restore alias variables:

$ mumps -run tprollback
tprollback    ;
    ZPrint    ; Print this program
    Set A(1)=1,A(2)=2,A(3)=3
    Set B(1)="1b",*B(2)=A,B(3)=3 ; B includes a container for A
    Set *C(1)=B             ; C includes a container for B
    Kill *A,*B             ; C is the only way to the data
    Write "------------",!
    Write "Only containers before transaction:",!
    ZWRite
    TStart (C)
    If '$TRestart
    .Set *D=C(1)    ; D is now an alias for what used to be B
    .Set D(3)=-D(3)
    .Set *D=D(2)    ; D is now an alias for what used to be A
    .Set D(1)=-D(1)
    .Kill *D        ; Kill D after is used to manipulate the arrays
    .Write "------------",!
    .Write "Changed values before restart:",!
    .ZWRite
    .TRestart
    Write "------------",!
    Write "Restored values restart:",!
    ZWRite
    Kill C ; Kill only handle to arrays
    Write "------------",!
    Write "No local arrays left:",!
    ZWRite
    TROllback ; Rollback transaction, don't commit it
    Write "------------",!
    Write "Rollback doesn't restore names and local arrays",!
    ZWRite
    Quit
------------
Only containers before transaction:
$ZWRTAC=""
*C(1)=$ZWRTAC1
$ZWRTAC1(1)="1b"
*$ZWRTAC1(2)=$ZWRTAC2
$ZWRTAC2(1)=1
$ZWRTAC2(2)=2
$ZWRTAC2(3)=3
$ZWRTAC1(3)=3
$ZWRTAC=""
------------
Restored values restart:
$ZWRTAC=""
*C(1)=$ZWRTAC1
$ZWRTAC1(1)="1b"
*$ZWRTAC1(2)=$ZWRTAC2
$ZWRTAC2(1)=1
$ZWRTAC2(2)=2
$ZWRTAC2(3)=3
$ZWRTAC1(3)=3
$ZWRTAC=""
------------
No local arrays left:
------------
Rollback doesn't restore names and local arrays
$

$ZAHandle()

$ZAHANDLE() returns a unique identifier (handle) for the array associated with a name or an alias container; for an subscripted lvn, it returns an empty string.  To facilitate debugging, the handle is a printable string representation of a hexadecimal number.   The only meaningful operation on the value returned by a call to $ZAHANDLE() is to compare it for equality with the value returned by another call.  Changing nodes within the array doesn't change its handle.  $ZAHANDLE() returns different results for copies of an array.

GTM>Set A=1,*B(1)=A

GTM>Write "$ZAHandle(A)=""",$ZAHandle(A),""" $ZAHandle(B(1))=""",$ZAHandle(B(1)),""""
$ZAHandle(A)="17B8810" $ZAHandle(B(1))="17B8810"
GTM>Set A("Subscript")="Value" ; Change array - but $ZAHandle() doesn't change

GTM>Write "$ZAHandle(A)=""",$ZAHandle(A),""" $ZAHandle(B(1))=""",$ZAHandle(B(1)),""""
$ZAHandle(A)="17B8810" $ZAHandle(B(1))="17B8810"
GTM>Merge D=A ; A copy of the data has a different $ZAHandle()

GTM>Write "$ZAHandle(A)=""",$ZAHandle(A),""" $ZAHandle(D)=""",$ZAHandle(D),""""      
$ZAHandle(A)="17B8810" $ZAHandle(D)="17B8C10"
GTM>

Since GT.M does not provide a way for a function to return an array or alias variable as its result, the uniqueness of $ZAHandle() can be exploited to effect this capability, by placing the result in a local variable with an agreed prefix (e.g., "%") and its $ZAHANDLE() as a suffix.  The handle can be returned as the value.

$ mumps -run retval
retval        ; Return an array / object from a function
    ;;Data for the object array
    ;;Albert Einstein,14-March-1879
    ;;Arthur Eddington,28-December-1882
    ;;
    ZPRint    ; Print this program
    New tmp1,tmp2,tmp3
    For i=3:1 Set tmp1=$Text(+i),tmp2=$Piece(tmp1,";;",2) Quit:'$Length(tmp2)  Do
    .Set tmp3="%"_$$NewPerson($Piece(tmp2,",",1),$Piece(tmp2,",",2))
    .Set @("*Relativists("_(i-2)_")="_tmp3)
    .Kill @("*"_tmp3)
    Kill tmp1,tmp2,tmp3
    Write "------------",!
    Write "Array of objects of relativists:",!
    ZWRite
    Quit
    ;    
NewPerson(name,birthdate)    ; Create new person object
    New lname,fname,dob,tmp1,tmp2 ; New variables used by this function
    Set lname=$Piece(name," ",2),fname=$Piece(name," ",1)
    Set dob=$$FUNC^%DATE(birthdate)
    Set tmp1("fname")=fname,tmp1("lname")=lname,tmp1("dob")=dob
    Set tmp2=$ZAHandle(tmp1)
    Set @("*%"_tmp2_"=tmp1")
    Quit tmp2
------------
Array of objects of relativists:
$ZWRTAC=""
*Relativists(1)=$ZWRTAC1
$ZWRTAC1("dob")=13952
$ZWRTAC1("fname")="Albert"
$ZWRTAC1("lname")="Einstein"
*Relativists(2)=$ZWRTAC2
$ZWRTAC2("dob")=15337
$ZWRTAC2("fname")="Arthur"
$ZWRTAC2("lname")="Eddington"
i=5
$ZWRTAC=""
$

$ZDATA()

$ZDATA() extends $DATA() to reflects the current alias state of the lvn or name argument to identify alias and alias container variables.  It treats variables joined through pass-by-reference as well as TP RESTART variables within a transaction as alias variables.  However, it does not distinguish nodes having alias containers among their descendants.

In addition to the four standard M results from $DATA(), $ZDATA() returns:

101 for an alias or alias container with no descendants
111 for an alias or alias container with descendants

Existing $DATA() tests for data and descendants report on alias and alias container variables, as well as other variables in the standard fashion. When an application uses alias and alias container variables $ZDATA() supplies additional information when needed.

GTM>Set a=1,*b(1)=a,*c=d

GTM>Write $Data(a)," ",$ZDATA(a)
1 101
GTM>Write $Data(b)," ",$ZDATA(b)
10 10
GTM>Write $Data(c)," ",$ZDATA(c)
0 100
GTM>Write $Data(d)," ",$ZDATA(d)
0 100
GTM>Write $Data(b(1))," ",$ZDATA(b(1))
1 101
GTM>Set b(1,2)=2

GTM>Write $Data(b(1))," ",$ZDATA(b(1))
11 111
GTM>Write $Data(b(1,2))," ",$ZDATA(b(1,2))
1 1
GTM>

View

VIEW now provides the following (additional) keywords, recognized as valid case-insensitive evaluations of its expression argument:


There are no visible effects from invoking these operations, except for the passage of time.

GTM>View "stp_GCOL","lv_gcol","lv_rehash"

GTM>

Depending on the state of your process, this example can require GT.M do a lot of work behind the scenes.

FIS uses these VIEW facilities in testing.  They are documented here primarily to ensure completeness in product documentation.  You may (or may not) find them useful during application development for debugging or performance testing implementation alternatives.

$View()

$VIEW() now provides the following (additional) keywords, recognized as valid case-insensitive evaluations of its first expression:


FIS uses these $VIEW() facilities in testing and documents them to ensure completeness in product documentation.  You may (or may not) find them useful during application development for debugging or performance testing implementation alternatives.  The following example creates an alias variable and an alias container variable and checks the number of both container references and total references to the cells associated with both a and b:

GTM>Set a=1,*b(1)=a

GTM>Write $View("LV_CREF","a")," ",$View("LV_CREF","b")
1 0
GTM>Write $View("LV_REF","a")," ",$View("LV_REF","b")  
2 1
GTM>

This example creates two cross associated alias containers, destroys their ancestor nodes with KILL * and uses $VIEW("LV_GCOL") to force a clean-up of the abandoned data-spaces. In the absence of the $VIEW("LV_GCOL"), GT.M would do this automatically at some subsequent convenient time:

GTM>Set *a(1)=b,*b(1)=a

GTM>Kill *a,*b

GTM>Write $View("LV_GCOL")
2
GTM>

Annotated Extended Alias Example

$ mumps -run aliasexample
aliasexample    ; Extended annotated alias example
    ZPrint
    Write "------------",!
    Set x="name level",x(1)=1,x(1,2)="1,2",x("foo")="bar"
    Write $ZDATA(x),! ; x is a conventional lvn - output 11
    Set *y=x ; x an y are now alias variables
    Write $ZDATA(x),! ; output appears as 111
    Set *a(1)=y ; a(1) is now an alias container variable
    Set b="bness",b("b")="bbness" ; b is a conventional lvn
    Set *b=a(1) ; b joins x and y as alias variables for the same data
    ; prior b values are lost
    ; Set *<name> is equivalent to Kill *<name> Set *<name>
    Set y("hi")="sailor" ; Assignment applies to all of {b,x,y}
    Kill b("foo") ; Kill applies to all of {b,x,y}
    Kill *x ; x is undefined and no longer an alias variable
    ; b and y still provide access to the data
    Write a(1),"<",! ; output appears as <
    Write a(1)*3,! ; output appears as 0
    Write $Length(a(1)),! ; output appears as 0
    Set c=y,c("legs")="tars" ; c is conventional lvn with value "name level"
    Do sub1
    Write $Data(c),! ; output is 1
    Do sub2(.c)
    Set a(1)="" ; a(1) ceases to be an alias container variable
    ; has the value ""
    Write $D(i),! ; output is 0
    Kill *c,*y ; c and y become undefined lvns
    ZWRite b ; output is b("got")="a match"
    ; it's no longer an alias variable
    ; as everything else has gone
    Quit
sub1
    New y ; in this scope y is no longer an alias for b
    Set *y=c ; in this scope c and y are alias variables
    Kill y("legs") ; Kill apples to all of {c,y}
    Kill *y ; in this scope y is no longer an alias for c
    ; this is really redundant as
    ; the Quit implicitly does the same thing
    Quit
sub2(i) ; i and c are joined due to pass-by-reference
    Write $ZAHandle(c)=$ZAHandle(i),! ; output appears as 1
    Kill b ; data for {b,y} is gone
    ; both are undefined, but remain alias variables
    Set *c=a(1) ; c joins {b,y} as alias variable; prior value of c lost
    ; c is no longer alias of i
    Write $ZAHandle(c)=$ZAHandle(i),! ; output appears as 0
    Set i=a(1) ; Assignment applies to i - value is ""
    Set c("got")="a match" ; Assignment applies to all of {b,c,y)
    Quit
------------
11
111
<
0
0
1
1
0
0
b("got")="a match"
$