わたしは仕事ではずっとC++を使ってきたので基本的にC++アタマです。その観点からRubyをみるといろいろ面白いですね。Rubyに比べると、Javaは随分C++に近い言語だなあとも感じます。

Abstractなメソッドを定義できない

ちょっとコードを書いてみてまず目につくのは、Rubyには仮想関数がないってことです。JavaやC#のインタフェースに相当するものもありません。

GoFのパターンでいうAbstractFactoryやらStateやらStrategyでは

  1. インタフェースを定義して、
  2. 同じインタフェースを備えているけど振る舞いが異なる複数の実装クラスを用意

します。C++はインタフェースはないけれども、全てのメソッドが純粋仮想であるようなクラスを書けばよいですな。でもRubyではどうすればいいんだ?

Rubyでは型チェックが行われない

型チェックが行われない、というとウソになりますね。実行前(コンパイル時、パース時)にはチェックされないというのが正しいでしょう。

しかしC++プログラマから見ると、感覚的には「Rubyは型チェックが行われない」ように見えます。ほとんどの場面では型よりも、そのオブジェクトがどんなメッセージに反応できるかってことのほうが重要です。

Duck Typing

全く型に関連がなくても同じメソッドを備えていれば、それは事実上同じ型として扱えると考えるのがDuckTypingです。「アヒルのように鳴き、アヒルのように歩くものはアヒルに違いない」といわけです。

StateパターンをRubyで実現しようと思ったら自然とDuckTypingになります。ConcreteState同士は型的には無関係だけど、そのStateに要求されるメソッドを用意しておけばよいわけです。

Rubyなひと(や、Smalltalkなひと)からすれば自然なんでしょうが、C++ばっかりだった私には新鮮な考え方でした。

C++では無理だよなあ...。と思っていたらやり方がありました。テンプレートを使うときはDuckTypingになってますね。

template <T>
class DoSomethingExecutor {
public execute(T obj) {
obj.doSomething();
}
}

Tに要求されるのは、引数のないdoSomething()というメソッドが存在することだけで、型はなんでもOKですね。とはいえテンプレートを駆使して例えばConcreteStateの型がお互い関連のないStateパターンを実現するのは非常に困難ですね。

宣言不要

Rubyでは変数の型宣言が不要、メソッドの引数にも型が不要ですし、インスタンス変数ですら必要になったときに登場させればよいのです。インスタンス変数は@で始まるというルールは潔いです。コードコンベンションでインスタンス変数は小文字mではじめる、なんて決めるよりいいですよね。

attr_accessorは宣言ぽいですが、一行書くだけでC#でいうところのget/setを備えたプロパティが用意されると思うと楽するための宣言と思えます。普通はattr_accessorとかattr_readerを用意すれば十分で、排他とか値変換とかややこしいことがしたくなったらはじめて、C#でいうプロパティっぽいメソッドを用意すればいいわけです。

書いてみてどうよ?

楽です。速いです。モデルを考えるときには抽象クラス(あるいはインタフェース)があるほうが考えやすいですが、実装時に抽象クラスを書く作業は苦痛です。なんの仕事もしないけど型を定義するためだけに書くのですから。

宣言不要なのも楽な要素です。「この引数はどんな型にしよう?」とか悩む前にかけちゃいます。書いてから悩んでもいいわけです。

上にあげた以外でも、Rubyは短く簡潔に書けることが多いです。一番よく使うのがコレクションクラスのeachやらallやらmapにクロージャを渡す書き方です。

convertedArray = anArray.map { | x | MyConverter.convert(x) }

なんてやると、anArrayの各要素をconvertした結果の配列がconvertedArrayに入ります。イテレータを作ってそれに対して云々、ってやり方がものすごくまどろっこしくなります。

デメリットは?

動的型チェックはC++プログラマには不安です。モジュール内部で使っているメソッドの引数を変更しよう、ってなときはコンパイラのエラーに頼って修正することもありますし。しかしUnitTestが正しく書かれていれば、型の問題はほとんどチェックできるようにも思います。UnitTestが失敗したときに、それが型の問題によるものだ、というのが即座に分からないことはありそうに思いますが。

チーム開発だと他に問題があるかもしれません。どのようなデメリットがあるのか(あるいはないのか)を実感するためには実際に経験をつまないとわからなさそうです。