Bug #2516
closedIO#reopen Compatibility (original: [ruby-dev:39479])
Description
=begin
takkanmさんとなかださんの[ruby-dev:39479]のスレッドによると、IO#reopenのnilの問題は解決したものの、いつのまにか挙動が変更されていたとのことです。
この変更は意図的なものなのか意図していないものなのかどちらなのでしょう。
% cat test.rb
f1 = File.open "file1.txt"
f2 = File.open "file2.txt"
f1.reopen f2
puts f1.gets
puts f1.gets
puts(f1.reopen(f2).gets)
% ruby -v
ruby 1.8.7 (2009-06-12 patchlevel 174) [i686-darwin9]
% ruby test.rb
Line 1
Line 2
Line 1
% ruby -v
ruby 1.9.2dev (2009-10-17 trunk 25387) [i386-darwin9.8.0]
% ruby test.rb
Line 1
Line 2
Line 3
このissueは #1755 にも関連しています。
http://redmine.ruby-lang.org/issues/show/1755
意図したものならば、この変更をRubySpecにも反映させます。
個人的には現状の挙動が嬉しいです。¶
=end
Updated by mame (Yusuke Endoh) almost 15 years ago
=begin
遠藤です。
IO#reopen について調べているのですが、さっぱりわかりません。
$ cat foo.txt
1
2
3
1.8: 途中位置の File に reopen したら読み込めない¶
f1, f2 = File.new("foo.txt"), File.new("foo.txt")
f2.gets
f1.reopen(f2)
p f1.gets #=> nil
p f1.gets #=> nil
p f1.gets #=> nil
p f1.pos #=> 2
1.9: reopen した後は get 早い者勝ち? pos の結果が違う¶
f1, f2 = File.new("foo.txt"), File.new("foo.txt")
f1.reopen(f2)
p f1.gets #=> "1\n"
p f2.gets #=> nil
p f1.pos #=> 2
p f2.pos #=> 2
f1, f2 = File.new("foo.txt"), File.new("foo.txt")
f1.reopen(f2)
p f2.gets #=> "1\n"
p f1.gets #=> nil
p f1.pos #=> 6
p f2.pos #=> 2
reopen の想定ユースケースってどんなんでしょうか。
dup2 のようなものかと思っていたのですが、そんな挙動でもないですよね。
ユースケース次第では、reopen の引数に渡された IO は close してしまう
方が混乱しなくてすむと思います。
できればユースケースの議論の前に挙動が変わった理由を把握したかった¶
のですが、何がバグで何が仕様かわかりませんでした。¶
--
Yusuke Endoh mame@tsg.ne.jp
=end
Updated by kosaki (Motohiro KOSAKI) almost 15 years ago
=begin
2010年2月11日15:24 Yusuke Endoh redmine@ruby-lang.org:
チケット [ruby-dev:39479]) (Rejected)" href="/issues/2516">#2516 が更新されました。 (by Yusuke Endoh)
遠藤です。
IO#reopen について調べているのですが、さっぱりわかりません。
$ cat foo.txt
1
2
3# 1.8: 途中位置の File に reopen したら読み込めない
f1, f2 = File.new("foo.txt"), File.new("foo.txt")
f2.gets
f1.reopen(f2)
p f1.gets #=> nil
p f1.gets #=> nil
p f1.gets #=> nil
p f1.pos #=> 2# 1.9: reopen した後は get 早い者勝ち? pos の結果が違う
f1, f2 = File.new("foo.txt"), File.new("foo.txt")
f1.reopen(f2)
p f1.gets #=> "1\n"
p f2.gets #=> nil
p f1.pos #=> 2
p f2.pos #=> 2f1, f2 = File.new("foo.txt"), File.new("foo.txt")
f1.reopen(f2)
p f2.gets #=> "1\n"
p f1.gets #=> nil
p f1.pos #=> 6
p f2.pos #=> 2reopen の想定ユースケースってどんなんでしょうか。
dup2 のようなものかと思っていたのですが、そんな挙動でもないですよね。
ユースケース次第では、reopen の引数に渡された IO は close してしまう
方が混乱しなくてすむと思います。できればユースケースの議論の前に挙動が変わった理由を把握したかった¶
のですが、何がバグで何が仕様かわかりませんでした。¶
Linuxだと同等の以下のCプログラムが
#include <stdio.h>
int main(void)
{
FILE *f1, *f2;
char buf[80];
f1 = fopen("inputfile", "r+");
printf("%s", fgets(buf, 80, f1));
f2 = freopen("inputfile", "r+", f1);
printf("%s", fgets(buf, 80, f1));
printf("%s", fgets(buf, 80, f1));
printf("%s", fgets(buf, 80, f1));
printf("pos %d\n", ftell(f1));
printf("pos %d\n", ftell(f2));
}
こうなります。
1
1
2
3
pos 6
pos 6
内部的には struct FILEが struct _IO_marker をポイントしていて、 _IO_markerは共有、そっちでpos管理している。
また SUSをみると
http://www.opengroup.org/onlinepubs/009695399/functions/freopen.html
最初に引数streamをflushしてcloseするよん。とか書いてあるけど、Linuxは単にdupしてるだけなんでcloseしてないみたい。なんか互換性の理由があるのかな?
IO系は見るからに標準Cライブラリの影響が色濃いので、これに合わせればいいんじゃないでしょうかねぇ・・・
nalshさんあたりが悲鳴を上げる恐れがありますが。
=end
Updated by mame (Yusuke Endoh) almost 15 years ago
=begin
遠藤です。
2010年2月15日13:25 KOSAKI Motohiro kosaki.motohiro@jp.fujitsu.com:
反応がないので、誰も興味がないのだと判断します。遠藤さんとIRCで調整のうえ
kosakiがボールを握ることにしました。
現状 io.dup もposが狂った動きをしているので一緒に直すことになると思います。
IO とか興味ないのでよろしくお願いします。
あと、IRC で話した pos のとち狂った動きについて記録です。
○ pos が負になる
$ cat foo.txt
1
2
3
f1 = File.new("foo.txt")
f2 = File.new("foo.txt")
f2.gets
f1.reopen(f2)
f2.gets
f1.rewind
p f2.pos #=> -2
○ pos に副作用がある
f1 = File.new("foo.txt")
f2 = File.new("foo.txt")
f2.gets
f1.reopen(f2)
f2.gets
p f1.pos #=> 6
p f2.pos #=> 4
p f1.pos #=> 4
--
Yusuke ENDOH mame@tsg.ne.jp
=end
Updated by mame (Yusuke Endoh) over 14 years ago
- Status changed from Assigned to Rejected
=begin
遠藤です。
1.9.2 では仕様ということで reject します。([ruby-core:28335] 他)
わかりにくい挙動なことは確かなので、1.9.3 以降での改善を Feature
チケットとして別に登録しておきます。
--
Yusuke Endoh mame@tsg.ne.jp
=end