S-JIS[2011-07-24] 変更履歴

Scala 型一致チェック

Scalaで型(型パラメーター)AとBが等しいかどうかをコンパイル時にチェックする方法を考えてみる。

type A = java.util.Date
type B = 〜

上記のような型が宣言されているとき、Bがjava.util.Date以外(例えばjava.sql.Date)だとコンパイルエラーにしたい。


代入によるチェック

その型の変数を定義して、代入できればOKなはず。
必ずしもnewでインスタンスを作れるとは限らないので、値はnull(初期値)を使う。

var a: A = _
var b: B = _
a = b
b = a

親クラス・子クラスの関係が逆転するかもしれないので、逆の代入も試す必要がある。

動作は問題なさそうだけど、4行もかかってる(苦笑) (セミコロンで区切れば1行に収められはするけど)


Classによるチェック

クラスが一致していることのチェックなら、Classが等しいかどうかを調べればいいか。

assert(classOf[A] == classOf[B])

ただ、これだと実行しないと分からない。(コンパイル時のチェックにならない)

C言語なら#ifで…出来るんかな?


型パラメーター制約によるチェック

Generalized Type Constraintsに「=:=」という“型が等しいときだけOKとする制約”がある。これを使えないだろうか。

def check(implicit ev: A=:=B){}

…これだけだと駄目だった(常にコンパイルは通る)。
この制約は呼び出し側でチェックされるので、呼び出しも入れてやらないといけない。

def check(implicit ev: A=:=B){}; check

というか、制約用インスタンスが生成できるかどうかが重要なので、暗黙のオブジェクトを取得するimplicitlyを使えばいい。

implicitly[A=:=B]

うん、これが一番シンプルだ(笑)

コンストラクター内に書くと実行時に(大したロスじゃないだろうけど)実行されてしまうので、さらにチェック用メソッドの中に書くのが良さそう。

class Foo {
  type A = java.util.Date
  type B = java.util.Date

  private def typeCheck = implicitly[A=:=B]
}

Scala実験へ戻る / Scala目次へ戻る / 技術メモへ戻る
メールの送信先:ひしだま