S-JIS[2011-07-24] 変更履歴
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が等しいかどうかを調べればいいか。
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] }