引数

この章では、Curl® 言語の関数呼び出しの引数について説明します。具体的には、以下の項目について説明します。
このセクションの内容は、関数と総称されるグローバル プロシージャ、匿名プロシージャ、クラス プロシージャ、メソッド、コンストラクタおよびファクトリーに関するものですが、説明を分かりやすくするために以下の例ではすべてグローバル プロシージャを扱っています。この章で説明する概念はテキスト書式およびテキスト プロシージャにも適用します。ただし、テキスト書式およびテキスト プロシージャの引数には異なる構文があります。

引数の概要

要約:
  • 2 つのカテゴリ:リストされた引数と残余引数
  • 2 つの形式:位置引数とキーワード引数
引数で関数に情報を渡すことができます。引数には次の2つのカテゴリがあります。
これらの引数のカテゴリには次の形式のいずれかまたは両方に渡される引数が含まれます。

位置引数の使用

要約:
  • 呼び出し元は各位置引数の値を指定する必要があります。
  • 呼び出し元は位置引数に対して正しい順序で値を指定する必要があります。
位置引数には次の構文があります。
arg-name[:arg-type]
説明:
位置引数の定義の例は次のとおりです。
|| A procedure that takes one integer positional
|| argument (i)
{define-proc public {my-proc1 i:int}:void
    || Body of procedure
}

|| A procedure that takes one "any" positional
|| argument (a)
{define-proc public {my-proc2 a}:void
    || Body of procedure
}

|| A procedure that takes two positional arguments:
|| a bool (b) and a char (c)
{define-proc public {my-proc3 b:bool, c:char}:void
    || Body of procedure
}
関数呼び出しの数、データ型および位置引数の順序は、関数定義のそれらに一致させる必要があります。位置引数の値を与えるには、関数呼び出しで値を指定します。関数呼び出しで複数の引数を指定する場合は、カンマを使用して引数を区切ります。たとえば、次の例はすべて正規のプロシージャ コールです。
{my-proc1 13}
{my-proc2 13}
{my-proc2 'a'}
{my-proc2 "Hello"}
{my-proc2 true}
{my-proc3 true, 'a'}

キーワード引数の使用

要約:
  • 呼び出し元は各キーワード引数の値を指定する必要はありません。
  • 各キーワード引数定義には既定値が含まれます。
  • 呼び出し元は、キーワード引数に対して任意の順序で値を指定することができます。
キーワード引数には次の構文があります。
arg-name[:arg-type]=arg-value
説明:
キーワード引数の定義の例は次のとおりです。
|| A procedure that takes one integer keyword
|| argument (i)
{define-proc public {my-proc4 i:int=0}:void
    || Body of procedure
}

|| A procedure that takes two keyword arguments:
|| a bool (b) and a char (c)
{define-proc public {my-proc5 b:bool=true, c:char='a'}:void
    || Body of procedure
}
関数の署名にキーワード引数を指定する場合は、関数を呼び出す際に、その引数に対して値を指定する必要はありません。キーワード引数の値を指定しない場合は、関数は既定値を使用します(arg-value)。キーワード引数の値を渡すには、関数呼び出しでその値を引数名に代入します。関数呼び出しで引数名を与えるので、キーワード引数を任意の順序で指定することができます。前述の my-proc5 プロシージャの場合、次の例はそれぞれ有効なプロシージャコールを示します。
{my-proc5}
{my-proc5 b=true}
{my-proc5 c='q'}
{my-proc5 b=true, c='q'}
{my-proc5 c='q', b=true}
キーワード引数が複数回指定される場合は、キーワード引数の最後に指定されるインスタンスが引数の連結に使用されます。他の値はすべて評価され、データ型が検査されてから捨てられます。
次に例を示します。

例: キーワード引数の使用
|| A procedure that returns the sum of two numbers.
{define-proc public {add-two-numbers number1:int=12, number2:int=13}:int
    {return number1 + number2}}

|| Call the procedure, supplying the arguments.
{add-two-numbers}
{add-two-numbers number1=12}
{add-two-numbers number2=13}
{add-two-numbers number1=12, number2=13}
{add-two-numbers number2=13, number1=12}
{add-two-numbers number2=69, number1=12, number2=13}
       
以下の例では、引数と uninitialized-value-for-type の初期バインディングを説明します。 同名のグローバル変数を使用して、キーワード引数の既定値の設定を試みます。 グローバル変数名が uninitialized-value-for-type (整数の場合は 0)にバインドされているキーワード名により覆われているため、 この試みは失敗します。

例: 初期キーワード バインディング
{let number1:int = 12}
{let number2:int = 13}
|| A procedure that returns the sum of two numbers.
{define-proc public {add-two-numbers 
                        number1:int = number1, 
                        number2:int = number2}:int
    {return number1 + number2}}

{add-two-numbers}

位置引数とキーワード引数の使用

要約:
  • 関数定義では、位置引数およびキーワード引数を任意の順序で指定することができます。
  • 関数呼び出しには、関数定義と同じ順序で位置引数を指定しますが、キーワード引数は任意の順序で指定します。
関数を位置引数およびキーワード引数で定義するのに、位置引数およびキーワード引数を任意の順序で指定することができます。たとえば、次のコードでは add-two-numbers プロシージャの署名に 1 つの位置引数 (number1) および 1 つのキーワード引数 (number2) が含まれます。
{define-proc public {add-two-numbers number1:int, number2:int=13}:int
    {return number1 + number2}
}
関数を位置引数およびキーワード引数で呼び出す場合、キーワード引数を任意の位置と順序で指定することができます。ただし、関数定義と同じ順序で位置引数を指定する必要があります。位置引数間にキーワード引数を含めることができます。ただし、位置引数の相対順序を相互に保持する必要があります。次の例で、上述のプロシージャを呼び出すことができるさまざまな方法をいくつか示します。

例: キーワード引数と位置引数の使用
|| A procedure that returns the sum of two numbers.
{define-proc public {add-two-numbers number1:int, number2:int=13}:int
    {return number1 + number2}
}

|| Call the procedure, supplying the arguments.
{add-two-numbers 12, number2=13}
{add-two-numbers number2=13, 12}
{add-two-numbers number2=69, 12, number2=13}

リストされた引数

要約:
  • 引数はすべて関数定義内に表示されます。
  • 引数は位置フォーマットまたはキーワード フォーマットを持つことができます。
リストされた引数は関数定義に表示されます。リストされた引数は位置引数またはキーワード引数の形式になります。たとえば、次のプロシージャの定義にはリストされた引数が 2 つあります (arg1 および arg2)。リストされた引数はいずれも位置引数です。
{define-proc {my-proc arg1:int, arg2:int}:bool
    {return arg1 == arg2}
}
また、次のプロシージャの定義にはリストされた引数が 2 つあります (arg1 および arg2)。この場合は、リストされた引数のいずれもキーワード引数です。
{define-proc {my-proc arg1:int=13, arg2:int=19}:bool
    {return arg1 == arg2}
}
最後に、次のプロシージャの定義にはリストされた引数が 3 つあります (arg1, arg2 および arg3)。この場合は、リストされた引数の内 2 つは位置引数で、残りの 1 つはキーワード引数です。
{define-proc {my-proc arg1:int, arg2:bool, arg3:int=19}:bool
    {return (arg1 == arg3) and arg2}
}

残余引数

,
要約:
  • 引数のリストの最後にある3つのピリオド (...) は関数が残余引数を受け取ることを示します。
  • 引数は位置フォーマットまたはキーワードフォーマットを持つことができます。
  • キーワード引数が複数回指定される場合は、関数は最後に指定された引数を使用します。
  • 残余引数にデータ型をオプションで指定することができます。ただし、データ型を指定するとキーワード引数を受け取ることができません。
  • 特別な形式の for ループを使用して残余引数のコンテナの引数にアクセスします。
残余引数により、関数は名前のない引数を無制限に受け取ることができます。残余引数は関数定義では個々に名前は付けられません。そのかわり、関数定義の引数リストの最後にある 3 つのピリオド (...) は、関数が残余引数を受け取ることを示します。
(...) が、関数定義に表示されると任意の数の残余引数が関数呼び出しの際に指定されます。必要に応じて、引数を一切指定しないこともできます。リストされた引数と同様に、残余引数は位置引数またはキーワード引数の形式になります。
残余引数は実際には残余引数コンテナに格納されます。... がコンテナを示します。残余引数は、すべて遭遇される順番でコンテナに格納されます。次に、コンテナで繰り返し処理をして引数にアクセスすることができます。重複するキーワード引数は残余引数コンテナ内で連結されません 。つまり、キーワード引数が複数回指定されると、残余引数のメカニズムにより、発生したものがすべて格納されるということです。
残余引数のデータ型をオプションで指定することができます。データ型を指定すると、残余引数はキーワード引数を含むことができないので、引数はそれぞれ指定のデータ型を持つ必要があります。たとえば、次のコードは一連の残余引数を定義します。各引数は String データ型を持ちます。
...:String

関数定義に残余引数を指定

残余引数を指定する場合は、3 つのピリオド (...) を引数リストの最後に含めます。次に例を示します。
|| A procedure that takes rest arguments.
{define-proc public {my-proc6 ...}:void
    || Body of procedure
}

|| A procedure that takes two keyword arguments:
|| a bool (b) and a char (c) and rest arguments.
{define-proc public {my-proc7 b:bool=true, c:char='a', ...}:void
    || Body of procedure
}
残余引数のデータ型を指定することもできます。この指定は非常に有用です。次に例を示します。
|| A procedure that can take any number of int arguments
{define-proc public {my-int-proc ...:int}:void
    || Body of procedure
}

残余引数での処理

残余引数コンテナ内の引数にアクセスするには、特別な形式の for ループを使用します。この形式の for ループ構文は次のとおりです。
{for (val-identifier, key-identifier) [key loop-counter] in ... do
statements
}
説明:
呼び出し元が指定した残余引数にキーワード引数が含まれない場合は、次の構文を使用します。
{for val-identifier [key loop-counter] in ... do
statements
}
実行時に for ループに遭遇すると、残余引数コンテナで引数ごとに statements が繰り返し実行されます。次に例を示します。

例: 残余引数での処理
|| A procedure that takes rest arguments and returns a StringBuf.
{define-proc {my-proc ...}:StringBuf
    || A variable to hold the return value of the procedure.
    let result:StringBuf = {StringBuf}
    || For each value in the rest arguments container, concatenate
    || the value to the string and append a space to the end
    || of the string.
    || Note that this loop will generate a runtime error if the
    || rest arguments container has a keyword argument (or, in
    || fact, any argument that is not a StringInterface, which is
    || the base class for strings in the Curl language).
    {for v in ... do
        {result.concat v}
        {result.append ' '}
    }
    || Return the string
    {return result}
}

{value
    || Some strings.
    let s1:String = "Here"
    let s2:String = "comes"
    let s3:String = "Curl!"

    || Call the procedure, supplying the strings as rest arguments.
    {my-proc s1, s2, s3}
}
他の関数呼び出しでは残余引数コンテナを引数として渡すことができることに留意してください。次に例を示します。

例: 残余引数コンテナを引数として渡す
|| A procedure that takes rest arguments and returns a VBox.
{define-proc {my-vbox ...}:VBox
    || Return a call to VBox with the rest arguments container
    || as the first argument.  Because the "background"
    || and "spacing" arguments appear after the rest
    || arguments container, these settings will always take
    || effect (even if the same keyword argument appears
    || in the rest arguments container).  You can use this
    || technique to ensure that default settings are applied,
    || even if other values are specified as rest arguments.
    {return {VBox ..., background="pink", spacing=5pt}}
}

{value
    || Call the procedure, supplying the following rest arguments:
    ||  1) a keyword argument indicating the background color of
    ||     the VBox
    ||  2) a keyword argument indicating the alignment in the VBox
    ||  3) a String to place in the VBox
    ||  4) a Button to place in the VBox
    ||  5) a String to place in the VBox
    ||  6) a keyword argument indicating the margin of the VBox
    {my-vbox
        background="beige",
        halign="center",
        "Hello World",
        {CommandButton label="Click Me!"},
        "Goodbye",
        margin=5pt
    }
}

残余引数の記述

残余引数は関数定義内に反映されないので、初期の残余引数の内容を明示的に記述する必要があります。これにより、関数を呼び出す引数に正しい残余引数が指定されているかどうかを容易に確認することができます。残余引数を記述する際、次を指定する必要があります。

呼び出しに残余引数を指定

残余引数を取る関数を呼び出す場合は、指定する引数を決定する関数の記述をチェックします。Curl 言語の構文により残余引数の指定はオプションになります。

残余引数とパフォーマンス

要約:
  • 残余引数コンテナを引数として関数呼び出しに渡す場合は、呼び出される関数が残余引数を取ることを確認してください。
  • 位置引数および残余引数を取る関数を呼び出す場合は、関数に必要な位置引数の数を指定します。
  • 関数呼び出しで引数として渡す、残余引数コンテナ内でのキーワード引数の使用を避けてください。
関数呼び出しの引数の処理には、システム リソースがコンパイル時および実行時に必要になります。こうしたリソースの要件は重要でない場合がほとんどです。ただし、プログラム実行中にシステムへの過度の要求を引き起こしかねない残余引数の一定の使用は避ける必要があります。
残余引数コンテナを関数呼び出しの引数として渡す場合は、呼び出される関数が残余引数を取ることを確認します。関数呼び出しの最後の引数は残余引数コンテナで、呼び出す関数の引数リストの最後の引数が残余引数であることも確認します。
位置引数および残余引数を取る関数を呼び出す場合は、関数に必要な位置引数の数も指定します。これによって、新しい残余引数コンテナを作成する必要がなくなります。たとえば、次のコードのように、barfoo の呼び出しは、bazfoo の呼び出しよりもさらに効率的に処理されます。
|| A procedure that takes one positional argument and
|| rest arguments.
{define-proc {foo x:int, ...}:void
    || Body of procedure.
}

|| Efficient use of rest arguments: the call to "foo"
|| has one positional argument and the rest arguments
|| container.
{define-proc {bar ...}:void
    {foo 37, ...}
}

|| Inefficient use of rest arguments: the call to "foo"
|| has a positional argument, another positional
|| argument, and the rest arguments container.
{define-proc {baz ...}:void
    {foo 37, 94, ...}
}
関数呼び出しで引数として渡す残余引数コンテナ内でのキーワード引数の使用を避けます。使用するとかなり非効率な処理になります。

引数クラス

要約:
  • Curl 言語では、Arguments クラスを使用して関数呼び出しの引数を処理します。
  • 残余引数コンテナと同様 Arguments オブジェクトは引数を保持するコンテナです。
Curl 言語では、Arguments クラスを使用して引数コンテナを最初のクラス値として処理します。Arguments クラスを使用して Arguments オブジェクトを作成することができます。Arguments オブジェクトは実際に引数を保持するコンテナです (残余引数コンテナが引数を保持するコンテナと同様)。たとえば、次のコードでは Arguments オブジェクトを定義し、それをいくつかの位置引数およびキーワード引数で初期化しています。
let args:Arguments = {Arguments background = "beige",
                                color = "blue",
                                "Here...",
                                "comes..."}
Arguments クラスのフィールドおよびメソッドを使用して、コンテナの引数を処理することができます。詳細については、『API リファレンス』の Arguments の説明を参照してください。 Arguments コンテナの引数を関数呼び出しの引数として渡す場合は、この章の次のセクションで説明する splice 式を使用することができます。
残余引数コンテナと同様、特別な形式の for ループ型を使用して Arguments オブジェクトの引数にアクセスできます。この特別な形式の for ループ構文は次のとおりです。
{for (val-identifier, key-identifier) [key loop-counter] in arg-object do
statements
}
説明:
Arguments オブジェクトにキーワード引数が含まれている場合は、必ず key key-identifier 構文を含めてください。含めないと実行時エラーが発生します。
実行時に for ループに遭遇すると、順次 Arguments オブジェクトの要素を繰り返し、引数ごとに statements が実行されます。

splice

要約:
  • splice を使用してコンテナを取り、コンテナの要素を引数のリストとして返します。
  • 配列、文字列、キュー、セット、ハッシュテーブル、Arguments オブジェクトおよび残余引数コンテナなどのさまざまなコンテナで splice を使用することができます。
  • コンパイラは単に splice 式を引数リストの形式でコンテナの要素に置き換えるので splice 式を引数リストとして処理することができます。
Curl 言語には、コンテナを取りその要素を引数リストに挿入する splice と呼ばれる特別な式があります。この式により、コンテナの要素を関数呼び出しの引数として容易に指定することができます。たとえば、splice 式を使用して、配列の全要素を関数呼び出しの引数として含めることができます。splice 式を使用して関数の Arguments オブジェクトと同様にコンテナの内容を渡すこともできます。for ループで繰り返し処理されるコンテナで splice を使用することができます。そのようなコンテナには、配列、文字列、キュー、セット、ハッシュテーブル、Arguments オブジェクトおよび残余引数コンテナが含まれます。コンパイラは単に splice 式を引数リストの形式でコンテナの要素に置き換えるので splice 式を引数リストとして処理することができます。
これは、C、 C++ および Java™ などの他のプログラミング言語にはない非常に強力な機能です。splice 式を含むソース コードをコンパイルすると、コンパイラは splice 式を引数リストの形式でコンテナの要素に置き換えます。ただし、パラメータリストのコンテキストのみに splice 式を使用できることに注意してください。それを汎用的に使用してコンテナの要素にアクセスすることはできません。
splice 式には次の構文があります。
{splice container-name}
container-name はコンテナ名です。配列、文字列、キュー、セット、ハッシュテーブル、Arguments オブジェクトおよび残余引数コンテナなど、Curl 言語のほとんどのコンテナで splice を使用することができます。たとえば、my-array と呼ばれる Array に対して splice を呼び出すには次の構文を使用します。
{splice my-array}
splice 式は関数呼び出しの引数リストのコンテキスト内にのみ表示されます。上記の例は適切なコンテキスト内で次のようなものになります。
{my-proc {splice my-array}}
コンパイラは単に splice 式を引数リストの形式でコンテナの要素に置き換えるので splice 式を引数リストとして処理することができます。つまり、splice 式を引数リストの任意の位置に含めることができます。たとえば、次の splice 式の使用はすべて有効です。
{my-proc {splice my-array}}
{my-proc {splice my-array}, arg-n}
{my-proc arg-1, arg-2, {splice my-array}}
{my-proc arg-1, arg-2, {splice my-array}, arg-n}
関数呼び出しの引数に対する 2 つの共通のコンテナで splice 式を使用することができます。残余引数コンテナ(...) と Arguments オブジェクトこれらの引数コンテナのいずれかで splice 式を使用すると引数の順序を保持して位置引数およびキーワード引数を返します。ただし、splice を残余引数コンテナで使用すると冗長になり、残余引数コンテナが同じフォーマットで引数を返します。次の例で、位置引数およびキーワード引数が含まれる Arguments オブジェクトによる splice の使用を示します。

例: Arguments オブジェクトによる splice の使用
{value
    || Define an Arguments container and initialize it with
    || a number of positional and keyword arguments.
    let args:Arguments = {Arguments background = "beige",
                                    color = "blue",
                                    "Here...",
                                    "comes..."}

    || Define a VBox and initialize it with the return value
    || from a call to the spaced-vbox procedure.
    || A "splice" expression includes the arguments from the
    || Arguments object initialized above.
    let vb:VBox = {spaced-vbox
                      "Hello world!",
                      {splice args},
                      "Curl!"}

    || Display the VBox
    vb
}
特に引数を保持するために設計されていないコンテナで使用すると、splice 式は位置引数として要素を返します。この場合に、コンテナによりキーワード構文がサポートされ、キーワードが含まれます。splice 式が、特に引数を保持するために設計されていないコンテナでキーワードに遭遇すると、キーワードは無視されます。
次の例は、配列による splice の使用を示します。

例: 配列による splice の使用
{value
    || Define an array of strings and initialize it with
    || three strings.
    let some-strings:StringArray =
        {new StringArray, "Here...", "comes...", "Curl!"}

    || Define a VBox and initialize it with the return value
    || from a call to the spaced-vbox procedure.
    || A "splice" expression includes the elements of the
    || array initialized above as arguments in the procedure call.
    let vb:VBox = {spaced-vbox
                      "Hello world!",
                      {splice some-strings}}

    || Display the VBox.
    vb
}
splice 式の使用をさらに理解するには、String の配列内容を連結する問題を考慮します。StringBuf を作成して文字列の中間内容を保持することができます。次に、配列要素を繰り返し String をそれぞれStringBuf に連結することができます。最後に、StringBufString に変換することができます。ただし、splice 式を使用して、単に配列要素を String の呼び出しの引数として指定することができます。次に例を示します。

例: 文字列による splice の使用
{value
    || Define an array of strings and initialize it with
    || three strings.
    let some-strings:StringArray =
        {new StringArray, "Here...", "comes...", "Curl!"}

    || Define a String and initialize it with the return value
    || from a call to splice.  The "splice" expression includes
    || the elements of the array defined above.
    let output-string:String = {String {splice some-strings}}

    || Display the String.
    output-string
}