Chapter 8. ドット記号オーバーロード

多くのプログラミング言語では、一般的にいわゆるドット表記は与えられたタプル値、レコード値、オブジェクト値のフィールドを選択するために使われます。ATS では、パターンマッチもしくはドット表記の使用によってフィールドを選択することができます。例えば、次のコードはフラットなタプルとボックス化タプルをコンストラクトしています。そして、それらの構成要素を選択するためにドット表記を使っています:

// val tup_flat = @("a", "b") val tup_boxed = $tup("a", "b") // val-"a" = tup_flat.0 and "b" = tup_flat.1 val-"a" = tup_boxed.0 and "b" = tup_boxed.1 //

ATS では、ドット表記で複数の関数を呼び出すために、それらの関数名で特定のドット記号をオーバーロードすることができます。その結果、タプルやレコードのフィールド選択のようにコードがよめるようになります。このスタイルの関数呼び出しは、ときに、ATS で書かれたコードをより読み易いものにするでしょう。またそれは ATS とオブジェクト指向プログラミング言語を相互呼び出しする際に顕著です。

オーバーロードにおけるドット表記の例として、2次元空間の点を表わす非線形抽象型 point を導入し、さらに関連する関数群を宣言してみましょう:

// abstype point = ptr // boxed // extern fun point_make (x: double, y: double): point // extern fun point_get_x (p: point): double and point_get_y (p: point): double // extern fun point_set_x (p: point, x: double): void and point_set_y (p: point, x: double): void //

関数 point_get_xpoint_get_y を呼び出すことで、与えられた点の X 座標と Y 座標をそれぞれ得ることができます。関数 point_set_xpoint_set_y を呼び出すことで、与えられた点の X 座標と Y 座標をそれぞれ設定できます。ドット記号 .x.y を導入し、それらを次のような関数名でオーバーロードします:

symintr .x .y overload .x with point_get_x overload .x with point_set_x overload .y with point_get_y overload .y with point_set_y

すると次のコードに示すように、対応する get 関数と set 関数の呼び出しにドット表記を使うことができます:

val p0 = point_make (1.0, ~1.0) val x0 = p0.x() // point_get_x (p0) and y0 = p0.y() // point_get_y (p0) val () = p0.x := y0 // point_set_x (p0, y0) and () = p0.y := x0 // point_set_y (p0, x0)

代入におけるドット表記は void 値を返す関数のみ参照できることに注意してください。上記の例では、関数 point_set_xpoint_set_y は両方とも void 値を返します。 また、上記で示したオーバーロードされたドット表記は非線形の値にのみ適用できることを強調しなければなりません。線形値を扱うためには、わずかな制限が要求されます。これは次に説明します。

カウンタオブジェクトを表わす線形抽象型 counter と関連するいくつかの関数を導入しましょう:

// absvtype counter = ptr // extern fun counter_make (): counter extern fun counter_free (counter): void // extern fun counter_get (cntr: !counter): int extern fun counter_incby (cntr: !counter, n: int): void //

予想されることですが、関数 counter_makecounter_free はカウンタオブジェクトの生成と破棄をそれぞれ表わします。関数 counter_get は与えられたカウンタに保管されている現在のカウントを返し、関数 counter_incby は与えられた整数値でそのカウントを増やします。

次のようなオーバーロード宣言を導入したとしましょう:

// overload .get with counter_get overload .incby with counter_incby //

期待されたるように、これで次のように counter_get を呼び出すことができます:

val n0 = c0.get() // = counter_get(c0)

同様に、c0 に保管されているカウンタを 1 増やすために、次のように counter_incby を呼び出すことができます:

val () = c0.incby(1) // = counter_incby(c0, 1)

もし (非線形の) point の例に戻るのであれば、次のコードもまた型検査に成功します:

val p0 = point_make (1.0, ~1.0) val x0 = p0.x() // point_get_x (p0) and y0 = p0.y() // point_get_y (p0) val () = p0.x(y0) // point_set_x (p0, y0) and () = p0.y(x0) // point_set_y (p0, x0)

ドット表記の一般的な形式と区別するために、私はこの形式のドット表記を 関数的なドット表記 と呼ぶことがあります。

この章で示したコード全体とテストコードは オンライン から入手できます。