kなんとかの日記 このページをアンテナに追加

2008-09-24

なぜ File.read() でなくて IO.read() なのか? なぜ File.read() はあって File.write() はないのか?

| 00:02 |  なぜ File.read() でなくて IO.read() なのか? なぜ File.read() はあって File.write() はないのか?を含むブックマーク

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() が用意されないなんて、なんか納得がいかない。

まつもとまつもと 2008/09/25 06:32 納得できるかどうかはともかく、IOがそうなのは歴史的事情で、最初からpathを扱うものはFileに、という設計だったらそれはそれで良かったのでしょうが、過去にこの点についてIOでもpathを扱うとしてしまったので、今さら変更するほどのメリットはないなあ、というのが正直な点です。

File.writeについては、read系と違ってFile.writeはモード指定なしには動作しないことが多いので、

File.write(path, str, mode)

っていうのは私としてはどうなんだろうなあって感じです。openへの引数が分断されているのが、変な感じ。

それでもいいのだ、という話もあるでしょうが、1.9.1にはちょっと時間が足りないかなあ。1.9.2あたりを目指してロビーするとか。

kwatchkwatch 2008/09/26 07:26 まつもとさん、ruby-talkに続きコメントありがとうございます。

> 納得できるかどうかはともかく、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 あたりに掲載されているとうれしいんですが。

まつもとまつもと 2008/09/26 11:20 昔はRCRとかあったんですけど、もう使われてないんで、今はredmineのfeature requestに突っ込んでからMLで議論するというのが手順ですね。

トラックバック - http://d.hatena.ne.jp/kwatch/20080924/1222268571