パラメータ渡し
パラメータ渡し
プロシージャの重要な特徴は、パラメータ渡しに対するサポートです。これは、プロシージャに値または変数をパラメータとして渡すための機能です。当然のことながら、パラメータ渡しは必須ではありません。例えば、パラメータ渡しとしていないプロシージャを使用して、乱数の生成や、既定以外の形式でシステム日付を返す操作などが可能です。それでも、多くの場合、プロシージャではパラメータ渡しを使用します。
パラメータ渡しを設定するには、以下を指定します。
-
プロシージャ呼び出し時の実パラメータ・リスト
-
プロシージャ定義時の仮パラメータ・リスト
Caché がユーザ定義プロシージャを実行するとき、実パラメータ・リストのパラメータが、それに対応する仮リストのパラメータに位置を基準としてマップされます。したがって、実リストの先頭にあるパラメータの値は仮リストの先頭にある変数に配置され、2 番目の値は 2 番目の変数に配置され、以降の値も同様に配置されます。これらのパラメータの照合は、名前ではなく、パラメータの位置で行われます。したがって、実パラメータに使用する変数と仮パラメータに対して使用する変数は、同じ名前を持つ必要はありません (また、通常持つべきではありません)。プロシージャでは、渡された値に該当する変数を仮リストの中で参照することにより、渡された値にアクセスします。
実パラメータ・リストと仮パラメータ・リストの間で、収録されているパラメータの数が異なっていることがあります。
-
実パラメータ・リストにあるパラメータが、仮パラメータ・リストにあるパラメータより少ない場合、仮パラメータ・リストと一致しない要素は未定義となります。以下の例のように、未定義の仮パラメータに使用するデフォルト値を指定できます。
Main /* Passes 2 parameters to a procedure that takes 3 parameters */ SET a="apple",b="banana",c="carrot",d="dill" DO ListGroceries(a,b) WRITE !,"all done" ListGroceries(x="?",y="?",z="?") { WRITE x," ",y," ",z,! }
-
実パラメータ・リストにあるパラメータが、仮パラメータ・リストにあるパラメータより多い場合は、以下の例のように、<PARAMETER> エラーが発生します。
Main /* Passes 4 parameters to a procedure that takes 3 parameters. This results in a <PARAMETER> error */ SET a="apple",b="banana",c="carrot",d="dill" DO ListGroceries(a,b,c,d) WRITE !,"all done" ListGroceries(x="?",y="?",z="?") { WRITE x," ",y," ",z,! }
仮リストにある変数が実リストにあるパラメータよりも多く、既定値が各パラメータに指定されていない場合、余った変数は未定義のままとなります。プロシージャのコードに適切な If テストを記述し、プロシージャの各参照で、使用可能な値が得られることを確認する必要があります。実パラメータ数と仮パラメータ数の一致を簡素化するには、可変個数のパラメータを指定します。
実パラメータの最大数は 254 個です。
ユーザ定義プロシージャにパラメータを渡す場合は、値渡しまたは参照渡しが可能です。同じプロシージャの呼び出しの中で、値渡しと参照渡しを混用できます。
-
プロシージャには、パラメータを値で渡すことも参照で渡すこともできます。
-
サブルーチンには、パラメータを値で渡すことも参照で渡すこともできます。
-
ユーザ定義関数には、パラメータを値で渡すことも参照で渡すこともできます。
-
システム関数には、パラメータを値でのみ渡すことができます。
値渡し
値渡しをする場合は、実パラメータ・リストでリテラル値、式、またはローカル変数 (添え字付きでも添え字なしでも可) を指定します。式を指定した場合、Caché は最初にその式を評価し、次に結果の値を渡します。変数名を使用する場合、Caché からはその変数の現在の値が渡されます。指定したすべての変数名が必ず存在し、値が設定されている必要があります。
プロシージャの仮パラメータ・リストには、添え字なしのローカル変数名を記述します。このリストで明示的な添え字付き変数を指定することはできません。一方、可変個数のパラメータを指定すると、添え字付き変数が暗黙的に作成されます。
Caché は、プロシージャで使用される非パブリック変数をすべて暗黙に生成、宣言します。したがって、呼び出し元のコードで同じ名前を持つ既存の変数は上書きされません。これらの変数の既存の値 (存在する場合) をプログラム・スタックに置きます。QUIT コマンドを呼び出すとき、Caché は各仮変数に対して暗黙の KILL コマンドを実行し、スタックから前の値を復元します。
以下の例で、SET コマンドは 3 つの異なる形式を使用して、参照先の Cube プロシージャに同じ値を渡します。
DO Start()
WRITE "all done"
Start() PUBLIC {
SET var1=6
SET a=$$Cube(6)
SET b=$$Cube(2*3)
SET c=$$Cube(var1)
WRITE !,"a: ",a," b: ",b," c: ",c,!
QUIT 1
}
Cube(num) PUBLIC {
SET result = num*num*num
QUIT result
}
参照渡し
参照渡しの場合、以下の形式を使用して、実パラメータ・リストのローカル変数名あるいは添え字なしの配列名を指定します。
.name
参照渡しでは、プロシージャでまだ参照していない段階であれば、指定された変数名または配列名が実際に存在している必要はありません。参照渡しは、配列名をプロシージャに渡すことができる唯一の方法です。なお、添え字付き変数は参照渡しできません。
-
実パラメータ・リスト : 実パラメータ・リストのローカルな変数名または配列名の前にはピリオドを記述する必要があります。これは、変数が値ではなく、参照で渡されることを指定するものです。
-
仮パラメータ・リスト : 仮パラメータ・リストでは特殊な構文を必要とせずに、参照渡しで変数を受け取ります。仮パラメータ・リストでは、ピリオドを接頭語として使用することはできません。ただし、仮パラメータ・リストの変数名の前にアンパサンド (&) を接頭語として使用することはできます。規約により、この & 接頭語の使用は、変数が参照渡しされることを示します。& 接頭語はオプションであり、処理を実行するものではありません。ソース・コードを読みやすく、かつ保守しやすくするために役立つ規約です。
参照渡しでは、実リストの各変数および配列名が、関数の仮リストの対応する変数名に結合されます。参照渡しは、参照するルーチンと関数の間を双方向で通信する効果的なメカニズムを提供します。関数が仮リストにある変数を変更すると、対応する実リスト上の参照渡しの変数も変更されます。これは、KILL コマンドにも適用されます。仮リストにある参照渡しの変数が関数によって削除されると、対応する実リスト上の変数も削除されます。
実リストで指定した変数あるいは配列名が存在しない場合、関数参照により未定義として処理されます。関数が対応する仮リストの値を変数に代入すると、実の変数あるいは配列もこの値で定義されます。
以下の例では、参照渡しを値渡しと比較しています。変数 a を値で渡し、変数 b を参照で渡します。
Main
SET a="6",b="7"
WRITE "Initial values:",!
WRITE "a=",a," b=",b,!
DO DoubleNums(a,.b)
WRITE "Returned to Main:",!
WRITE "a=",a," b=",b
DoubleNums(foo,&bar) {
WRITE "Doubled Numbers:",!
SET foo=foo*2
SET bar=bar*2
WRITE "foo=",foo," bar=",bar,!
QUIT
}
以下の例では参照渡しを使用して、変数 result を通じて参照元のルーチンと関数の間で双方向通信します。ピリオド接頭語は、result が参照渡しされることを指定します。この関数を実行すると、実パラメータ・リストに result が作成され、関数の仮パラメータ・リストにある z にバインドされます。計算された値は z に代入され、result の参照元のルーチンに渡されます。仮パラメータ・リストの z に対する & 接頭語はオプションであり、機能もありませんが、ソース・コードの明確化に役立ちます。num と powr は、参照渡しではなく値渡しであることに注意してください。以下は、値渡しと参照渡しを組み合わせた例です。
Start ; Raise an integer to a power.
READ !,"Integer= ",num QUIT:num=""
READ !,"Power= ",powr QUIT:powr=""
SET output=$$Expo(num,powr,.result)
WRITE !,"Result= ",output
GOTO Start
Expo(x,y,&z)
SET z=x
FOR i=1:1:y {SET z=z*x}
QUIT z
可変個数のパラメータ
プロシージャでは、可変個数のパラメータが使用可能であることを指定できます。そのように指定するには、vals... のように最後のパラメータ名に 3 つのドットを付加します。このドットを付加するパラメータは、パラメータのリストの最後にあるものとする必要があります。パラメータのリストに記述した唯一のパラメータであってもかまいません。この ... 構文を記述することで、1 つ以上のパラメータを渡すことができるほか、パラメータをまったく渡さないこともできます。
リストのパラメータ間、ならびにリストの最初のパラメータの前と最後のパラメータの後には、スペースと新しい行が認められています。3 つのドットの間の空白は認められていません。
この構文を使用するには、最後のパラメータ名の後に ... が続くシグニチャを指定します。この手法でメソッドに渡す複数のパラメータには、データ型による値またはオブジェクトによる値を設定できるほか、これらの設定によるパラメータを混在して使用することもできます。可変個数のパラメータの使用を指定するパラメータには、任意の有効な識別子名を設定できます。
ObjectScript では、添え字付き変数を作成することで、可変個数のパラメータを渡す処理を扱います。この場合は、渡す変数ごとに 1 つの添え字が作成されます。最上位の変数には、渡すパラメータの個数を記述し、変数の添え字には、渡す値を記述します。
これを、以下の例に示します。ここでは、invals... を仮パラメータ・リストにある唯一のパラメータとしています。ListGroceries(invals...) は、可変個数の値を値渡しで受け取ります。
Main
SET a="apple",b="banana",c="carrot",d="dill",e="endive"
DO ListGroceries(a,b,c,d,e)
WRITE !,"all done"
ListGroceries(invals...) {
WRITE invals," parameters passed",!
FOR i=1:1:invals {
WRITE invals(i),! }
}
以下の例では、2 つの定義済みパラメータの後に最後のパラメータとして args... を使用しています。このプロシージャは、少なくとも 2 つのパラメータ値を受け取る必要があり、そのうえで可変個数のパラメータを追加で受け取ることができます。
Main
SET a=7,b=8,c=9,d=100,e=2000
DO AddNumbers(a,b,c,d,e)
WRITE "all done"
AddNumbers(x,y,morenums...) {
SET sum = x+y
FOR i=1:1:$GET(morenums, 0) {
SET sum = sum + $GET(morenums(i)) }
WRITE "The sum is ",sum,!
QUIT
}
以下の例では、2 つの定義済みパラメータの後に最後のパラメータとして args... を使用しています。このプロシージャが受け取るパラメータの個数は 2 つのみで、可変個数の追加パラメータ args... は 0 です。
Main
SET a=7,b=8,c=9,d=100,e=2000
DO AddNumbers(a,b)
WRITE "all done"
AddNumbers(x,y,morenums...) {
SET sum = x+y
FOR i=1:1:$GET(morenums, 0) {
SET sum = sum + $GET(morenums(i)) }
WRITE "The sum is ",sum,!
QUIT
}
指定に応じて、AddNumbers(x,y,morenums...) は 2 個以上、255 個以下の範囲でパラメータを受け取ることができます。定義済みのパラメータに既定値を指定して AddNumbers(x=0,y=0,morenums...) とすると、このプロシージャは 0 個以上、255 個以下の範囲でパラメータを受け取ることができます。
以下の例では、唯一のパラメータとして args... を使用しています。これは参照渡しで可変個数の値を受け取ります。
Main
SET a=7,b=8,c=9,d=100,e=2000
DO AddNumbers(.a,.b,.c,.d,.e)
WRITE "all done"
AddNumbers(&nums...) {
SET sum = 0
FOR i=1:1:$GET(nums, 0) {
SET sum = sum + $GET(nums(i)) }
WRITE "The sum is ",sum,!
QUIT sum
}
変数パラメータ・リスト params... が参照によって渡されたパラメータを受け取り、params... をルーチンに渡すと、その中間ルーチンは、参照によっても渡される追加パラメータ (params 配列の追加ノード) を追加できます。以下に例を示します。
Main
SET a(1)=10,a(2)=20,a(3)=30
DO MoreNumbers(.a)
WRITE !,"all done"
MoreNumbers(¶ms...) {
SET params(1,6)=60
SET params(1,8)=80
DO ShowNumbers(.params) }
ShowNumbers(&tens...) {
SET key=$ORDER(tens(1,1,""),1,targ)
WHILE key'="" {
WRITE key," = ",targ,!
SET key=$ORDER(tens(1,1,key),1,targ)
}
}
以下の例では、この args... 構文を仮パラメータ・リストと実パラメータ・リストの両方で使用できることを示しています。この例の可変個数のパラメータ (invals...) は、ListNums に値で渡され、そこで 2 倍の値にされたうえで invals... として ListDoubleNums に渡されます。
Main
SET a="1",b="2",c="3",d="4"
DO ListNums(a,b,c,d)
WRITE !,"back to Main, all done"
ListNums(invals...) {
FOR i=1:1:invals {
WRITE invals(i),!
SET invals(i)=invals(i)*2 }
DO ListDoubleNums(invals...)
WRITE "back to ListNums",!
ListDoubleNums(twicevals...)
WRITE "Doubled Numbers:",!
FOR i=1:1:twicevals {
WRITE twicevals(i),! }
QUIT
}
可変個数のパラメータの受け入れが可能なメソッドの詳細は、"Caché オブジェクトの使用法" の “メソッド” の章にある “メソッドに使用する可変長引数” のセクションを参照してください。