プロシージャの構文
ここでは、ObjectScript のルーチンで定義される、プロシージャの構文について説明します。
概要
プロシージャの構文は、以下のとおりです。
label(argumentlist) accessmode
{
implementation
}
または、
label(argumentlist) [pubvarlist] accessmode
{
implementation
}
以下はその説明です。
プロシージャ名。標準ラベルです。必ず 1 列目から始まります。引数がない場合も、label に続く括弧は必要です。
以下の形式の引数のコンマ区切りリストです。
argument1,argument2,argument3,...
引数は、次のように既定値を持つことができます。
argument1=default1,argument2=default2,argument3=default3,...
必要な引数は、仮引数リストと呼ばれます。プロシージャが引数を取らない場合でも、プロシージャ定義には括弧を含める必要があります。仮パラメータの最大数は 255 個です。
既定値はリテラル、つまり引用符で囲まれた数字あるいは文字列です。null 文字列 ("") も既定値として指定できます。null 文字列は変数を定義するため、これは既定値を指定しないこととは異なります。一方でパラメータ値が未指定の場合や既定値がない場合、変数は未定義となります。リテラル以外の既定値を指定すると、InterSystems IRIS は <PARAMETER> エラーを発行します。
パブリック変数です。プロシージャによって使用され、他のルーチンとプロシージャで使用できる、パブリック変数の任意のコンマ区切りリストです。これは、このプロシージャ内で定義され、他のルーチンでも使用可能な変数、あるいは他のルーチンで定義され、このプロシージャでも使用可能な変数のリストです。pubvar を指定する場合、それを角括弧で囲みます。pubvar を指定しない場合、角括弧は省略できます。パブリック変数には、このプロシージャに指定された引数を含めることができます。
ほとんどのプロシージャは、パブリック変数のリストを宣言しません。新しいコードでは、パブリック変数のリストは ObjectScript であまり使用されない機能です。
このプロシージャの使用法を制御するオプションのキーワードです。これは次のいずれかである必要があります。
-
PUBLIC キーワードは、このプロシージャがどのルーチンからでも呼び出しできることを宣言します。
-
PRIVATE キーワードは、このプロシージャが定義されたルーチン内でのみ呼び出されることを宣言します。既定は PRIVATE です。
例えば、以下はパブリック・プロシージャを定義します。
MyProc(x,y) PUBLIC { }
一方、以下の例はプライベート・プロシージャを定義します。
MyProc(x,y) PRIVATE { }
MyProc2(x,y) { }
ObjectScript コマンドです。左中括弧 ({) は、その後ろに続く先頭の文字から少なくとも 1 つのスペースを置く、あるいは 1 行の改行が必要です。同じ行の右中括弧 (}) の後ろにはコードを記述できず、ブランクあるいはコメントのみ置くことができます。通常、右中括弧は 1 列目に記述します。このコード・ブロックは、ラベルによってのみ入力されます。
関数としてのプロシージャ
ObjectScript プロシージャが値を返す場合、プロシージャは関数とも呼ばれます。このような関数は、組み込みの ObjectScript 関数 (内部関数とも呼ばれます) と区別するために、外部関数と呼ばれることもあります。
プロシージャから値を返すには、RETURN コマンドを使用します。
プロシージャ変数
プロシージャとメソッドは両方とも、プライベート変数とパブリック変数をサポートします。以下の文はすべてプロシージャとメソッドに同等に適用されます。
プロシージャ内で使用する変数は、自動的にプライベートになります。このプロシージャが呼び出すプロシージャの変数を共有したい場合、変数をパラメータとして他のプロシージャに渡します。
パブリック変数リスト
パブリック変数リストを介してパブリック変数を宣言することもできます。パブリック変数は、このプロシージャまたはメソッドの呼び出し元と呼び出し先のすべてのプロシージャおよびメソッドで使用できます。アプリケーションで環境変数として動作するよう、比較的少数のパブリック変数をこの方法で定義します。パブリック変数を定義するには、プロシージャ名とパラメータの後に角括弧内 ([ ]) で変数をリストします。
以下の例では、宣言された 2 つのパブリック変数 [a, b] と 2 つのプライベート変数 (c、d) が含まれるプロシージャが定義されます。
publicvarsexample
; examples of public variables
;
DO proc1() ; call a procedure
QUIT ; end of the main routine
;
proc1() [a, b]
; a private procedure
; "c" and "d" are private variables
{
WRITE !, "setting a" SET a = 1
WRITE !, "setting b" SET b = 2
WRITE !, "setting c" SET c = 3
SET d = a + b + c
WRITE !, "The sum is: ", d
}
USER>WRITE
USER>DO ^publicvarsexample
setting a
setting b
setting c
The sum is: 6
USER>WRITE
a=1
b=2
USER>
仮リスト・パラメータをパブリックにする
プロシージャに仮リスト・パラメータ (例えば MyProc(x,y) の x あるいは y) が存在し、それを他のプロシージャ (あるいはこのプロシージャ外のサブルーチン) で使用する場合は、それをパブリック・リストに置く必要があります。
以下はコードの例です。
MyProc(x,y)[x] {
DO abc^rou
}
y ではなく x の値が、abc^rou ルーチンで使用可能となります。
プライベート変数と NEW コマンドで生成される変数
プライベート変数は、NEW で生成される変数とは異なることに注意してください。プロシージャの変数を、他のプロシージャやサブルーチンで使用したい場合、その変数は必ず Public に宣言し、パブリック・リストに記述する必要があります。このプロシージャによってパブリック変数が導入されていれば、それに対して NEW を実行する意味があります。この場合、パブリック変数は、プロシージャが終了するときに自動的に破棄されます。しかし、パブリック変数が保持していた以前の値は保護されます。以下はコードの例です。
MyProc(x,y)[name]{
NEW name
SET name="John"
DO xyz^abc
}
name 変数はパブリックであるため、このコードによって、この変数の値 John を abc ルーチンの xyz プロシージャで参照できます。name に対して NEW コマンドを実行すると、MyProc プロシージャを呼び出したときに既に存在しているすべてのパブリック変数 name が保護されます。
NEW コマンドは、プライベート変数ではなくパブリック変数にのみ作用します。プロシージャ内で x がパブリック・リストになく、x が % 変数でない場合、NEW x または NEW (x) を指定すると違反になります。
プロシージャ・コード
中括弧内のコードがプロシージャのコードですが、従来の ObjectScript コードとは異なります。以下はその詳細です。
-
プロシージャに入ることができるのは、プロシージャ・ラベルの場所のみです。label+offset 構文を使ってプロシージャにアクセスすることはできません。
-
プロシージャのラベルは、プロシージャに対しプライベートであり、プロシージャ内からのみアクセスできます。PRIVATE キーワードは不要ですが、プロシージャ内のラベルで PRIVATE キーワードを使用できます。PUBLIC キーワードは、プロシージャ内のラベルで使用すると構文エラーが発生します。$TEXT システム関数は、プロシージャ・ラベル名を使用している label+offset をサポートしていますが、名前でプライベート・ラベルにアクセスできません。
-
ラベルの重複はプロシージャ内では許可されていませんが、特定の状況ではルーチン内で許可されています。特に、異なるプロシージャ内でラベルは重複して使用できます。また、同じラベルはプロシージャ内や、プロシージャが定義されたルーチン内の他の場所で表示できます。例えば、以下の 3 つの Label1 は使用できます。
Rou1 // Rou1 routine Proc1(x,y) { Label1 // Label1 within the proc1 procedure within the Rou1 routine } Proc2(a,b,c) { Label1 // Label1 within the Proc2 procedure (local, as with previous Label1) } Label1 // Label1 that is part of Rou1 and neither procedure
-
プロシージャにルーチン名なしの DO コマンドやユーザ定義関数がある場合、ラベルが存在しているとプロシージャ内のラベルを参照します。そうでない場合、ルーチン内ではあるがプロシージャの外部にあるラベルを参照します。
-
ルーチン名を持つ DO またはユーザ定義関数がプロシージャにある場合、そのプロシージャでは必ずその外部にある行を特定します。その名前がプロシージャを含むルーチンを識別する場合も同様です。以下に例を示します。
ROU1 ; PROC1(x,y) { DO Label1^ROU1 Label1 ; } Label1 ; The DO calls this label
-
プロシージャに GOTO が含まれる場合、プロシージャ内のプライベート・ラベルに移動する必要があります。GOTO では、プロシージャを終了できません。
-
label+offset 構文は、いくつかの例外はありますが、プロシージャ内ではサポートされていません。
-
$TEXT は、プロシージャ・ラベルから label+offset をサポートします。
-
Break またはエラー発生後にプロシージャに戻る方法として、GOTO label+offset を、プロシージャ・ラベルから始まるダイレクト・モード行で使用できます。
-
ZBREAK コマンドでは、プロシージャ・ラベルから始まる label+offset を指定できます。
-
-
プロシージャが終了すると、プロシージャが呼び出されたときに有効になっていた $TEST 状態が復元されます。
-
プロシージャの終了を意味する } は、行の最初の文字位置を含め、どの文字位置にでも置くことができます。コードは、行の } の前に記述します。その後ろには記述できません。
-
右中括弧の直前に、暗黙的な QUIT が置かれます。
-
間接指定と XECUTE コマンドは、プロシージャの範囲外に存在するかのように動作します。
プロシージャ範囲内の間接指定、XECUTE コマンド、および JOB コマンド
プロシージャ内の名前間接指定、引数間接指定、XECUTE コマンドは、プロシージャの範囲内では実行されません。したがって、XECUTE コマンドは、プロシージャ外にあるサブルーチンの暗黙的な DO のように動作します。
間接演算子と XECUTE は、パブリック変数にのみアクセスできます。その結果、間接演算子または XECUTE コマンドが変数 x を参照する場合、プライベート変数である x がプロシージャに存在していても、パブリック変数である x を参照します。以下に例を示します。
SET x="set a=3" XECUTE x ; sets the public variable a to 3
SET x="label1" DO @x ; accesses the public subroutine label1
同様に、間接指定または XECUTE で参照するラベルは、プロシージャ外のラベルです。プロシージャ内での GOTO は、その内部のラベルに移動する必要があるので、GOTO @A はプロシージャ内でサポートされていません。
間接演算と XECUTE コマンドの詳細は、このドキュメントの他の個所で説明されています。
同様に、プロシージャの範囲内で JOB コマンドを発行する場合、メソッド外の子プロセスを開始します。つまり、次のようなコードになります。
KILL ^MyVar
JOB MyLabel
QUIT $$$OK
MyLabel
SET ^MyVar=1
QUIT
子プロセスでラベルが見えるようにするには、プロシージャ・ブロックにメソッドまたはクラスを含めることはできません。
プロシージャ内でのエラー・トラップ
エラー・トラップがプロシージャ内から設定された場合、プロシージャのプライベート・ラベルに直接設定する必要があります。(これは、+offset やルーチン名を含む従来のコードとは異なります。この規則は、エラー・トラップの実行とは、基本的にエラー・トラップまでスタックを巻き戻し、GOTO を実行することである、という考えに一致しています。)
プロシージャ内でエラーが発生した場合、$ZERROR はプライベートの label+offset ではなく、プロシージャの label+offset に設定されます。
エラー・トラップを設定するには、通常の $ZTRAP を使用します。ただし、値はリテラルにする必要があります。以下はその例です。
SET $ZTRAP = "abc"
// sets the error trap to the private label "abc" within this block
エラー・トラップの詳細は、"TRY-CATCH の使用法" を参照してください。