昨日は日記を書けなかったわけだが、それは仕事が終わった後に会社の人たちに飲みに誘われて、そこで話し込んでしまって帰って来たのが 23:00 とかだったから。
まあそんなことはどうでもいいとして、ちょっと契約プログラミングの話。例えば Javadoc とかに次のような記述があるとする。
/**
* 何かするメソッド。
*
* @param s null でない文字列
*/
public hoge(String s) {
if (s.equals(...)) {
:
:
}
}
もしもこのメソッドに null を渡してエラーになったら、それはまあ基本的に渡した奴が悪いんだけど、俺はこういうのは「null を入れてはいけない」というルール・契約としてコードで表現したいのだ。多分 AspectJ とかのツールを使えばいいんだろうけど、俺はそういうバイトコード操作をするのは嫌いだ。あと契約を AspectJ のアスペクトで表現すると、実際のコードには反映されないってのが気に入らない。
というわけでいつも通り Python でならどうやるかという方向になるわけだが、これは関数デコレータを使うのがいいだろう。簡単に書くと次のような感じ。
def not_none_contract(f):
def _not_none(*args):
if None in args:
raise ContractError('None を入れるな')
r = f(*args)
# 事後条件のチェックをしたい場合はここで
return r
return _not_none
@not_none_contract
def foo(a, b):
:
:
@not_none_contract
def bar(a, b):
:
:
関数ならこれでいけるんだけど、じゃあスーパークラスのメソッドの契約をサブクラスでオーバーライドした場合もデフォルトで引き継がせるとなるとどうなるのかなあ。何となくそれは無理なんじゃないかという気がする。いや、 __getattribute__ に書いちゃうって手もあるけど、それはとても嫌だ。もっとも、オーバーライドしたメソッドが自動的に契約を引き継ぐのは契約の存在が明瞭じゃないので気持ち悪いといえばそうだ。
そして同じ事を Java でやろうとすると、えーとアノテーション使うのかな? あんまり使ったことないんでわからん。
この怪文書はクリエイティブ・コモンズ・ライセンスの元でライセンスされています。引用した文章など Kuwata Chikara に著作権のないものについては、それらの著作権保持者に帰属します。