息子が保育園に行くのを見てから就寝。 目が覚めるともう帰ってきていた。なんと夕方4時まで寝てしまったのだった。
何ヶ月かに一回、「Rubyにも(オプショナルな)型システムがほしい」というリクエストが来る。 大体はC++やJavaなど静的な型言語の経験がある人からのものである。曰く、
ま、わからんでもない。
が、元々は動的な型言語であるRubyにオプショナルな型を追加するのでは、 コンパイル時のチェックもさほど期待できないし、最適化も無理だろう。 となると、得られるメリットは最初のふたつということになる。 しかも、プログラムの読解には型よりもRDocなどによる適切なドキュメントの方が (嘘がなければ)より効果的だと思われる。
メリットばかりではない。通常、静的型システムはクラスをベースにして考える。
IO f
であれば、IOクラスまたはそのサブクラスのオブジェクトを受け付けるというような感じである。 ところが、これではfにStringIOオブジェクトを渡すことができなくなる。 StringIOはIOクラスと同じように振る舞うがIOのサブクラスではないからである。 つまり、たとえオプショナルでも静的型を導入することで柔軟性が減ってしまうということだ。 これは避けたい。
静的型言語では、多重継承やinterfaceを使って上記の問題を回避しようとしているし、 Rubyでもたとえばモジュールを使って解決可能ではあるが、 それでは手間が増えて嬉しさが減ってしまう。だったら最初からJavaを使えばよいんだし。
ところが、最近comp.lang.rubyで登場した提案は、 今までの「単なる静的型へのノスタルジー」をちょっと越えていた。 それは「型チェックをシグネチャで行う」ものだ。 これだと上記のデメリットがない。
もっとも、オプショナルとはいえ型システムは言語の性格を変える可能性があり、 しかも実装もそんなに楽ではない。 おまけにチェックによりパフォーマンスが低下する可能性が高いとなれば、 適切なエラーメッセージというメリットとのトレードオフを十分検討する必要があるだろう。
で、Jim Weirichからメソッド結合を使った提案が登場したのだが、 それについてはメソッド結合について解説してから取り上げよう。
追記
ツッコミにそれぞれ答えておこう。
まず、とんびさん。型があると補完ができるということですが、 Rubyはあまりに動的なのでオプショナルな型が少々あったくらいではお望みの補完は無理です。 プログラムの実行中にメソッドが増えたり減ったりすることが起きるのに適切な補完はできないでしょう。 逆にそこまで厳密でなくとも良いのならRDocの情報などをもとに補完するIDEは(原理的には)可能だと思います。
それから、mizuさん。offにするのはアリだとは思います。 ただ、オプショナルな型では穴が大きすぎでコンパイル時のチェックは行うことができず、 結局実行時チェックにならざるをえないことを考えると、どこまで嬉しいかどうかは疑問です。
mputさんのコメントはその通りなので、 最後、shugoさん。 こういうのをstructural conformanceというのか私はわからないのですが、 期待するメソッドを持っているかどうかだけでチェックし、継承関係を見ないという点では structural conformanceと呼べるかも。structuralという単語からは 「オブジェクトの構造(≒インスタンス変数など)」の方を連想しちゃうけど。