2012-02-09 (Thu) [長年日記]
_ 100人のプロが選んだソフトウェア開発の名著 君のために選んだ1冊
100人のプロが選んだソフトウェア開発の名著 君のために選んだ1冊
前に書いた記事が載っている本がAmazonで予約できるようになったみたい。
「来年度からプログラムを書く仕事をすることになってしまった不幸なおまえらの道標となるべき書籍十冊」みたいなエントリは読むな。という人もいるけど、まだ読んでないのでこの本にもあてはまるのかどうかよくわからない。
実は、紹介する本として最初に思い付いたのはThe Craft of Text Editing―手作りのテキストエディタだったんだけど、やはり絶版だったので、さすがに紹介するのはどうかなと思ってやめておいたのであった。 The Craft of Text Editingはエディタの本なのだが、多くの本と異なり、エディタを使う人のためではなく、作る人のために書かれている。 これを読んで、いつかRubyでエディタを作ってみたいと思いつつ、早十数年…ほら、やっぱり年寄の昔話になってしまった。
以下のサイトで英語版のPDFやEPUBを入手できるので、「NHK出版 ラジオ基礎英語1」の後で読んでみたら面白いかもしれない。
_ Rubyのfor式の失敗
前に書こうと思って忘れてたのだけど、shiroさんの記事を読んで思い出した。
Rubyにはfor式というものがあって、最近だとあまり好まれていないようだが、それはたぶん主に見た目の問題で、eachに対するたんなる構文糖だと思われている(ので直接eachを使った方がシンプルだと思われている)せいではないかと思われる。 しかし実は、Rubyのfor式はたんなる構文糖よりも少し罪が重い。それは、for式は変数のスコープを導入しない、つまり、ループ変数の破壊的な変更を前提にしている構文だということだ。
shiroさんの昔の記事の例でいうと、
irb(main):001:0> a = [] => [] irb(main):002:0> for i in 0..4 do a.push(lambda { i }) end => 0..4 irb(main):003:0> a => [#<Proc:0x2265df20@(irb):2 (lambda)>, #<Proc:0x2265ded0@(irb):2 (lambda)>, #<Proc:0x2265dea8@(irb):2 (lambda)>, #<Proc:0x2265de80@(irb):2 (lambda)>, #<Proc:0x2265de58@(irb):2 (lambda)>] irb(main):004:0> a.map {|i| i.call} => [4, 4, 4, 4, 4]
のようにlambdaでクローズしたつもりの変数の値がすべて最後の値に変更されてしまう。 eachを直接使うと、ブロックパラメータは毎回の呼び出し毎に別の変数になるので、こういう心配はない。
irb(main):005:0> a = [] => [] irb(main):006:0> (0..4).each do |i| a.push(lambda { i }) end => 0..4 irb(main):007:0> a => [#<Proc:0x2270c124@(irb):6 (lambda)>, #<Proc:0x2270c0fc@(irb):6 (lambda)>, #<Proc:0x2270c0d4@(irb):6 (lambda)>, #<Proc:0x2270c0ac@(irb):6 (lambda)>, #<Proc:0x2270be18@(irb):6 (lambda)>] irb(main):008:0> a.map {|i| i.call} => [0, 1, 2, 3, 4]
C#でも今から直すそうなので、(もっとユーザが少ないと思われる)Rubyでもたんなるeachの構文糖にしてしまうとか、Scala風のfor式にしてしまったらどうだろうか。