技術情報 - GT.Mエイリアス変数
Copyright © 2010 Fidelity Information Services, Inc.
Free Software Foundationによって公開されている
GNU Free Documentation License, Version1.3 またはそれ以降のバージョンで同意されたものとして、本マニュアルの修正版の複写と配布は、修正版全体が本許可告知と同一の条件のもとに配布される場合にのみ許可します。但し、「変更不可能部分」「おもて表紙テキスト」「うら表紙テキスト」など変更不可部分は含みません。
<s0>GT.M</s0>™ は、Fidelity Information Services, Inc. のトレードマークです。
このドキュメントではFISの任意のコミットメントは含まれません。この文書の情報は発表日現在において正確であると考えていますが、情報は予告なしに変更される場合があります。FISのすべてのエラーまたは欠陥について責任はありませんす。
改訂履歴
バージョン
|
日付
|
サマリ
|
1.0
|
2009年7月15日
|
最初の公開バージョン
|
GT.Mグループ
Fidelity National Information Services, Inc.
2 West Liberty Boulevard, Suite 300
Malvern, Pennsylvania 19355
アメリカ合衆国
|
GT.M Support for customers: +1 (610) 578-4226 / gtmsupport@fisglobal.com
Switchboard: +1 (610) 296-8877
Website: http://fis-gtm.com
|
目次
概要
V5.3-004の効果的な点として、GT.Mはエイリアス変数とエイリアスコンテナ変数のサポートを追加します。
エイリアス変数は、サブプログラムの呼び出し(DOコマンドまたは関数の呼び出し)で、Mによる参照渡しを与えることに類似する、ローカル変数の名前と配列の間にて抽象レイヤーを提供します。複数のローカル変数は、同じ配列へエイリアスすることができ、そして、1つの変数のSETやKILLは、すべての変数のSETやKILLとして作用します。エイリアスコンテナ変数は、任意の現在のローカル変数名を通じてアクセスできない時でさえも、連想配列を保護するそのデータセルを持つローカル変数の配列全体へ、参照を連想する方法を提供します。
GT.Mエイリアスは、アプリケーションがオブジェクト指向技術を実装することが可能な状況で、低レベルの機能を提供することを目指します。オブジェクトは、配列(array)に、マッピングを可能にし、そして、保存と操作を可能にし、次に、処理によりどこから取得できるのかを、エイリアスコンテナ変数に保存を可能にします。コンテナに使用される配列の適切な添字の使用は、コンテナの配列(array)を横断する$Order()関数を使用して、オブジェクトの格納とそれらの取得を編成する方法と提供します。エイリアス変数とエイリアスコンテナ変数がオブジェクトを移動するための MERGE コマンドを実行する必要を排除するので、オブジェクトを実装するためのエイリアス変数の使用することは、伝統的なローカル変数を超えて大幅な効率化を提供します。
新しい SET * および KILL * コマンドは、エイリアス変数とエイリアスコンテナ変数を操作します。
このドキュメント内では:
-
配列(array)は、M標準のその定義と非常に似ていて、ルートおよびすべての子孫を含むノードのツリー全体を意味しますが、しかし、このドキュメントでは、ローカル変数のみ適応しグローバル変数には適用しません。
-
"連想エイリアス変数" は、配列に関連付けられている、すべてのエイリアス変数とすべてのエイリアスコンテナ変数を意味します。
-
lvn は、M標準のその定義と非常に似ていますが、このドキュメントでは lvn は添字でのローカル変数名を参照する使用は除きます。
-
name は、M標準のその定義と非常に似ていますが、しかし、このドキュメントでは name が正しいローカル変数の名前であることを除きます(例えば、添字なしで)。
-
"データセル(Data cell) " と"ノード (node) " は同義語です。
エイリアス変数
エイリアス変数は複数のnames を介して配列へのアクセスを提供します。概念的なエイリアス変数は複数の変数名を接続する参照渡しとして同じです、エイリアス変数の接続が明示的であることを除き、それに対して、参照によって渡されたその変数は暗黙的です。実際、エイリアス変数の実装の基本とGT.M内の参照渡しは同じです。例:
GTM>Kill A,B
GTM>Set A=1,*B=A ; B & A are aliases
GTM>Write B
1
GTM>
-
同じ配列に関連付けられたすべてのエイリアスの変数はそのノードへアクセスしているそれらと同等です - 例えば、1つのnameを経由して1つの配列(array)の中でノードのSETは、エイリアスであるいくつかの他のnameを経由したノードへのSETとは、全く違っていません。それらの作成または連想はの順序については、何の意味を持ちません。
-
ひとたび、配列がシングルの添字無しnameだけを経由してアクセスが可能になると、GT.Mはそのnameを伝統的なローカル変数として扱います。
-
GT.Mは、エイリアス変数の特殊な変異体として参照渡しを介して接続した変数を扱います。参照渡しは、DO または $$ 呼び出しの副作用として出現する明示的なエイリアスと、QUITの副作用として暗黙的アンエイリアスとを持ち合わせてMスタックモデルと関連します。広義のエイリアスでは、プログラムコマンドは、任意のMスタック結合をせずに、直接 names をエイリアスとアンエイリアスします。
-
GT.Mは、もし作成しているトランザクションがRESTARTsする場合にのみが公開されるその内部のエイリアスとして、TP(トランザクション処理)RESTART変数の状態を扱います。
-
GT.Mは、エイリアスのタイプとして排他的なNEWによって、隠蔽された変数を扱います。
-
それらの暗黙的な振る舞いのために、ある状況下で、参照渡しのエイリアスと、RESTART変数と、排他的NEW エイリアスは、エイリアス変数を明白に作られることに関して完全な対称性はありません(例えば、それらは異なる時間に移り替わるかもしれないのに、ところが、エイリアス変数は、アプリケーションプログラムの制御の下で移り替わります)。
エイリアスコンテナ変数
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>
-
The value of an alias container is the empty string.
-
Use the SET * command to associate an name with the container to obtain access to the array in a container.
-
SET with an alias container as left-hand side target replaces the value at that node of the container variable and destroys any prior alias association with an array.
-
References to descendants of a alias container variable refer to nodes of the named parent array and have no relationship to any array contained by a parent node.
-
An alias container variable serves as a way to organize and manage entire arrays.
-
While it takes two alias variables for an array to be considered aliased, it only takes one alias container variable to do so.
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.
-
SET * left-hand side arguments cannot be parenthetically enclosed lists such as SET (a,*b)=c
-
SET and SET * assignments can be combined into one command in a comma separated list, e.g., SET *a=b,^c(3)=d(4)
-
SET * only accepts argument indirection, i.e., while SET x="*a=b",@x is permitted, neither SET x="*a",@x=b nor SET x="b",*a=@x is permitted.
-
SET * right-hand side arguments must be names, rather than any form of general expression (expr).
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>
エイリアスのコンテナの変数を作成することで、関連付けを作成するだけでなく、エイリアスのコンテナノードにデータを(空の文字列)を割り当てます:
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 は、どんなエイリアスの関連付けに影響を与えることなく、配列(および場合によっては配列自体)内のデータを削除します。
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
$
-
引数なしで KILL * をすると、すべてのエイリアスとエイリアスのコンテナの接続を削除します。
-
You can intermix KILL and KILL * in an argument list, e.g.: Kill *A,B
-
Kill * is not permitted inside a parenthesized list of exclusions, e.g.: KILL (*A) is an error.
-
An exclusive Kill where one associated name is inside the parenthetic list of exclusions and another associated name is not with that list kills the array through the name that is not inside the list. The association, however, is preserved:
GTM>Set A=1,*B=A ; Create an array and association
GTM>ZWRite ; Verify that it's there
A=1 ;*
*B=A
GTM>Kill (A) ; Kill everything except A
GTM>ZWRite ; Demonstrate that A also has no array
GTM>Set A=2 ; Create an array
GTM>ZWRite ; The association survived the Kill
A=2 ;*
*B=A
GTM>
パフォーマンス
With two exceptions, alias and alias container variables add no overhead to normal local variable performance:
-
Complex patterns of aliases layered onto TSTART RESTART variables.
-
Complex patterns of aliases intermixed with NEW scope management, particularly that using exclusive NEW.
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とZSHOW "V" は、2つの違いとして、概念的に類似しています:
-
ZWRITEは表示する変数と添字を指定するパターンの使用を許可するのに対し、ZSHOW "V" はすべてのローカル変数に適用されるます。
-
ZSHOW "V" は、オプションでグローバルまたはローカル変数へ指示するための出力を許可するのに対し、ZWRITEは常に現在の出力デバイスにその出力を指示します。
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>
この例に続いて、もしZWRITEコマンド用に選択された変数がエイリアス変数に関連付けられているいずれかが含まれていない場合、出力はデータではなくリファレンスのみ示しています。
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は大文字の非省略名と接頭辞$ZWRTACを認識だけします。
-
FIS strongly recommends that you not create or manipulate your own $ZWRTACn "variables". They are not part of the supported functionality for implementing alias variables and containers, but are rather a part of the underlying implementation that is visible to you, the GT.M user. FIS can arbitrarily , for its own convenience change the use of $ZWRTAC in GT.M at any time. They are only documented here since you may see them in the output of ZWRITE and ZSHOW "V".
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
$
排他的 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.
参照渡し
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
$
トランザクション処理
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.
$DATA()が返す4つの標準Mの結果に加え、$ZData() は以下のような値を返します:
下位ノードのないエイリアスまたはエイリアスのコンテナの場合は、101
下位ノードのあるエイリアスまたはエイリアスのコンテナの場合は、111
データと下位ノードのための既存 $DATA() のテストは、標準的な方法での他の変数だけでなく、エイリアスとエイリアスのコンテナの変数にレポートします。アプリケーションがエイリアスとエイリアスのコンテナ変数を使用する時、必要な場合は、$ZDATA() は追加情報を提供します。
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:
-
LV_GCOL - triggers a data-space garbage collection, which normally happens automatically at appropriate times
-
LV_REHASH - triggers a reorganization of the local variable look-up table, which normally happens automatically at appropriate times
-
STP_GCOL - triggers a string-pool garbage collection, which normally happens automatically at appropriate times
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:
-
LV_CREF - returns the number of references by alias containers to the array associated with an unsubscripted local variable name specified as a second expr (for example a quoted string); it returns a zero for a variable without any associated alias container
-
LV_GCOL - returns the number of data-spaces recovered during a local variable data-space garbage collection it triggers; such collections normally happen automatically at appropriate times
-
LV_REF - returns the total number of references to the data-space associated with an unsubscripted local variable name specified as a second expr (for example a quoted string)
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>
注釈:拡張エイリアスの例
$ 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"
$