implicit (プリミティブ)
パッケージ: CURL.LANGUAGE.COMPILER

暗黙の constructor または factory を指定します。

説明

クラスのコンストラクタとファクトリが 1 つの引数を取る場合、implicit キーワードを使用することにより、そのコンストラクタまたはファクトリーを使って引数型のインスタンスを暗黙的にクラス型に変換することができます。暗黙的なコンストラクションは、実行時型がクラスの暗黙的コンストラクタまたはファクトリーの型とマッチする値がクラス型の変数に代入された場合、または asa を使用してクラス型に明示的にキャストされた場合に発生します。次に例を示します。
{define-class A
  {constructor implicit {default val:String}}
}

let a:A = "hi" || invokes {A.default "hi"}
"hi" asa A     || invokes {A.default "hi"}

let a:A = 42   || bad assignment
暗黙のコンストラクタとファクトリーは、それらを呼び出さないと代入が許可されない場合のみに呼び出し可能で、暗黙のコンストラクタは暗黙的には呼び出されないので、暗黙のコンストラクタの引数型はクラス自体ではないか、またはそのクラスのサブクラスでない場合があります。 暗黙のコンストラクタとファクトリーはまた、それらが発生するクラスと同じアクセス機能を持つことが必要です。たとえば、クラスが public の場合、暗黙のコンストラクタまたはファクトリーも public でなければなりません。 クラス内の複数のコンストラクタまたはファクトリーを暗黙的とマークすることにより、異なる複数の引数型をクラス型に暗黙的に変換することができます。クラス内に複数の暗黙のコンストラクタまたはファクトリーがある場合は、呼び出す対象のコンストラクタまたはファクトリーは、実行時型の値が引数型のサブタイプである値で呼び出し可能な宣言を、順番に検索することによって選択されます。複数の暗黙のコンストラクタとファクトリーは、次のルールに従います。 位置引数を取らない一つのコンストラクタまたはファクトリーも implicit で宣言することが可能です。その場合、一つの型からクラス型への暗黙的な変換を許可する代わりに、コンストラクターを使用して暗黙的に初期化される非 null の変数が許可されます。
{define-class B
  {constructor implicit {default}}
}

let b1:B = {B} || explicit initialization
let b2:B       || implicitly initialized using {B.default}
let b3:#B      || implicitly initialized to null
null を使用して初期化されないので、これは特に Value クラス で便利です。 引数を取らない暗黙的なコンストラクタやファクトリーのサポートは、Curl API バージョン 6.0 で追加されました。

注意事項

暗黙のコンストラクタとファクトリーは、隠されているキャストのために動作の混乱やパフォーマンスのオーバーヘッドを容易に招く可能性があるので、その使用を最低限に抑えることが必要です。

allow-implicit-downcasts? compiler directive が false に設定されている場合(既定)、暗黙のコンストラクタのどれかが実行時に必ず呼び出されると判断できない限り、コンパイラは暗黙のコンストラクタによる暗黙のキャストを拒否します。たとえば、前述の例でクラス A の場合は次のようになります。

{define-proc {get-a-string}:StringInterface ...}
let a:A = {get-a-string}           || (1) error
set a = {{get-a-string}.to-String} || (2) ok
set a = {get-a-string} asa A       || (3) ok, explicit cast
{with-compiler-directives allow-implicit-downcasts? = true do
    set a = {get-a-string} || (4) ok, check disabled
}


最初の行はエラーになります。これは、get-a-stringA の暗黙のコンストラクタにパス可能な String を返す、ということがコンパイラで認識できないためです。3 行目は、asa を使用してキャストを明示的にするためエラーはありません。


{define-class public PhoneNumber
  field number:StringBuf
  {constructor implicit public {from-int64 val:int64}
    set self.number = {StringBuf val}
  }
  {constructor implicit public {from-StringBuf val:StringBuf}
    set self.number = val
  }
  {constructor implicit public {from-string val:StringInterface}
    || could validate number here, strip punctuation, etc.
    set self.number = {StringBuf val}
  }
  {constructor implicit public {default}
    set self.number = {StringBuf "?"}
  }
}

{let n1:PhoneNumber = 6177611200} || invokes from-int64
n1.number == {value n1.number}

{let n2:PhoneNumber = "6177611200"} || invokes from-string
n2.number == {value n2.number}

{let n3:PhoneNumber =
    {StringBuf "6177611200"} || invokes from-StringBuf
}
n3.number == {value n3.number}

{let n4:PhoneNumber} || initialized with default
n4.number == {value n4.number}

C++ プログラマへの注意

Curl における暗黙のコンストラクタとファクトリーは、C++ の単一引数コンストラクタで explicit キーワードを省略した場合と同様に動作します。Curl における暗黙のコンストラクタとファクトリーの C++ との主な違いは次の点です。
  • implicit キーワードを使用して、クラスの作成者によって明示的にリクエストされなければならない。
  • 呼び出す暗黙のコンストラクタまたはファクトリーの選択は、C++ における値のコンパイル時型ではなく、値の実行時型に依存する。