職場で定期的にやることになった Ruby 勉強会の資料作りをしていて、ブロック構文を投げてメソッド側から述語を呼ぶコールバック機能はいつから設計されているのかな、と気になって調べていました。
ドキュメントにも、以前から
(ブロック付きメソッドは)最初はループの抽象化のために用いられていたため、 特にイテレータと呼ばれることもあります。
メソッド呼び出し(super・ブロック付き・yield) (Ruby 2.3.0)
という記述があります。(現在では、File.open()
時の自動後処理や、Proc
や lambda
の述語的な記述用途でもあるので、必ずしもイテレータではないです)
いろんなページを見ていると、
という Ruby の歴史を分かりやすくまとめたページを見つけました。
最古の Ruby
今から20年以上前、1994年初夏のバージョン 0.49 が最古のスナップショットらしいです。下記からダウンロードすることができます。 (それ以上古いスナップショットは、Matzさんの転職のどたばたとHDDのクラッシュによって失われてそうです。)
ftp://ftp.ruby-lang.org/pub/ruby/1.0/
each メソッドはイテレータとして説明があるものの、サンプルで使っているところを見つけることができませんでした。 (意外なことにサンプル中の繰り返しは for ... in
構文を多用してます)
以下、spec ファイルにあったイテレータの説明です。
** イテレータ
イテレータとは制御構造(特にループ)の抽象化のために用いられるメソッドの 一種である. イテレータの呼び出しは以下の構文で行なわれる.
do 文1 using 変数 文2 end [ do ]
「文2」をブロックとして設定し, 文1のメソッドをイテレータとして評価 する. 文1のトップレベルのメソッドだけがイテレータとして呼び出され, レシーバを表す式や, 引数の式はイテレータとしては呼び出されない. 文 1に複数の式があれば各々がイテレータとして順に呼ばれる.
イテレータ内でyield valueが実行されると, その値がdo文で指定された変数 に代入されブロックが実行される. ブロックの実行が終了するとその値は yield式の値として返される. あるメソッドがイテレータとして呼び出された かどうかは関数iterator_p()で知ることができる. 中にはEnumerableモジュー ルのgrepメソッドのようにイテレータとして呼ばれた時と普通のメソッドとし て呼ばれた時とで動作が異なるメソッドもある.
for 変数 in 式 文 end [ for ]
式の各要素に対し文を実行する. これは以下のdo文と等価である. do (式).each using 変数 文 end よって式の値のオブジェクトがメソッドeachを持たない場合, forを実行 すると例外が発生する.
今の do |var| ... end
構文ではなく、do ... using var ... end
という形をしてたんですねー、面白い。 例外処理も begin ... end
ではなく protect ... end
で囲んであって色々と興味深いです。
最近の構文しか知らない方は、ぜひダウンロードして読んでみることをオススメします。
また Ruby でイテレータを、という考え方は設計段階からあったようです。
ずいぶん長い間いろいろな言語をつまみぐいして, よさそうなものを拾い集めてきました.rubyはそういう概念の集合 でもあります.例えば例外とかイテレータとか.
ちなみに C# は2005年暮れに発表された 2.0 まで、yield キーワードがなかったため、コルーチンすら 書けませんでした。こわい。
MLやCVSを詳しく追っていったわけではありませんが、ブロックを投げてなんでもやっちゃえる動きは、 その後の最適化、考え方の抽象化によって定着・進化していったのだと思いました。