2008-09-24
なぜ File.read() でなくて IO.read() なのか? なぜ File.read() はあって File.write() はないのか?
ruby | | ![]()
Ruby 1.9.1 仕様変更締め切りを記念して、Ruby で前々から疑問に思ってたことを書いてみる。
- (1) IO.read() は、なぜ IO.read() であって File.read() でないのか。引数に filename を取るんだから、filename に関係ない IO より、関係のある File のほうに定義すべきだったのではないか。
- (2) IO.read() はあるのに、なぜ IO.write() がないのか。PHP にだって file_get_contents() と file_put_contents() があるというのに、Ruby で IO.write() がないというのは対称性に欠ける。
comp.lang.rubyで聞いてみたけど、あんまり納得のいく回答がなかった。
- IO.read() じゃなくて File.read() と書けるよ
- → そんなことはわかってるし、答えになってない
- File.read() を自分で定義したライブラリを用意すればいい
- → これも答えになってない
- File.write() は File.read() より dangerous だから用意されてないのさ
- → File.unlink() はもっと危険なのに用意されているぞ
- IO.write() は、ファイルの先頭から書くのか後ろに追加するのかとか、バイナリモードにするかどうかなど、オプションがたくさんあって複雑になるから用意されていない
- → IO.read() だって、後ろの N バイトだけを読むとか先頭の N バイトを読み飛ばすとか考えられるし、バイナリモードだってある。
- File オブジェクトには << 演算子が使えるぞ
- File.open(filename, 'w'){|f| f << str } を使えといってるなら、これも答えになってない
なんかこう、いろいろ理由をこじつけているけど、どれも納得できる理由にはほど遠い。つうかさ、知らないなら知らないって答えればいいのに、なんでこんなに変なこじつけを考えるんだろうね。
・・・と思っていたら、なんとまつもとさんが降臨!
|I have questions about IO and File class.
|
|* Why is IO.read(filename) defined?
| IMO, File.read() is more natural than IO.read() because
| IO class is not related to filename, I think.
No big reason. Historically IO works on files, i.e. IO.open(path),
so that it was natural to provide these methods in IO too.
特に理由はないらしい。「IO works on files, i.e. IO.open(path)」の箇所はいまいち意味がわからないけど。
でもなあ、File#open(path) は filename を引数にとるけど、IO#open(fd) は file descriptor を引数にとるんだよな。
そう考えると、IO.open() が file descriptor ではなく filename を引数にとるのは違和感がある。
|* Is there any reason that IO.write() (or File.write()) is not
|provided?
| I have to define File.write() for each project...
| It is easy to define File.write() but I hope it is provided by Ruby.
For File.read(), when you want to specify file mode, you can just say:
File.read(path, "rb")
For File.write(), it is more likely to be:
File.write(path, str, "wb")
which makes me feel weird. In 1.9, we can write
File.write(path, str, mode: "wb")
which I feel slightly better.
matz.
これは最初、Ruby1.9 では File.write(path, str, mode: "wb") というのが用意されるのか! ヤッター! ・・・と読んでしまったが、そうではなかった。
やっぱり Ruby1.9 でも File.write() は用意されないみたいだ。
Symbol#to_proc は導入されるくせに File.write() が用意されないなんて、なんか納得がいかない。
- 34 http://www.rubyist.net/~kazu/samidare/
- 20 http://reader.livedoor.com/reader/
- 8 http://b.hatena.ne.jp/entrylist?sort=hot&of=50&threshold=3
- 7 http://www.google.com/reader/view/
- 5 http://blogs.wankuma.com/nagise/archive/2008/09/25/157505.aspx
- 5 http://kikyou.info/diary/
- 4 http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/kwatch/20080924/1222268571
- 4 http://b.hatena.ne.jp/entrylist?sort=hot
- 4 http://d.hatena.ne.jp/giuseppe/
- 4 http://d.hatena.ne.jp/k-z-h/20080920/p1
File.writeについては、read系と違ってFile.writeはモード指定なしには動作しないことが多いので、
File.write(path, str, mode)
っていうのは私としてはどうなんだろうなあって感じです。openへの引数が分断されているのが、変な感じ。
それでもいいのだ、という話もあるでしょうが、1.9.1にはちょっと時間が足りないかなあ。1.9.2あたりを目指してロビーするとか。
> 納得できるかどうかはともかく、IOがそうなのは歴史的事情で、最初からpathを扱うものはFileに、という設計だったらそれはそれで良かったのでしょうが、過去にこの点についてIOでもpathを扱うとしてしまったので、今さら変更するほどのメリットはないなあ、というのが正直な点です。
たしかに実用上問題となっているわけではないので、IO.read() をやめて File.read() にしたとしても、メリットがないのはおっしゃる通りです。
これは単に、統一感の問題です。Ruby での組み込みのクラスライブラリはよく考えられているので、たまにこういうおかしな点があると、どうしても気になってしまいます。
> File.writeについては、read系と違ってFile.writeはモード指定なしには動作しないことが多いので、
いえ、そんなことはありません。多くの場合は File.open(filename, ’w’) {|f| f.write(str) } で済みます。
・Ruby はテキスト処理に使われることが多いので、’w’ でよい (じゃないと File.read() の仕様が説明つかない)
・モード ’a’ が必要な場面では、file lock も必要なことが多く、そもそも File.write() という簡易メソッドがそぐわない
> File.write(path, str, mode)
>
> っていうのは私としてはどうなんだろうなあって感じです。openへの引数が分断されているのが、変な感じ。
なるほど。
でもこれは単に慣れの問題だと思います。path と mode が分断されていても、ふつうは気にしないんじゃないでしょうか。
> それでもいいのだ、という話もあるでしょうが、1.9.1にはちょっと時間が足りないかなあ。1.9.2あたりを目指してロビーするとか。
Ruby での仕様変更要求って、手順は決まっているんでしたっけ。
ruby-lang.org あたりに掲載されているとうれしいんですが。