Project

General

Profile

Bug #2516

IO#reopen Compatibility (original: [ruby-dev:39479])

Added by ujihisa (Tatsuhiro Ujihisa) over 9 years ago. Updated over 8 years ago.

Status:
Rejected
Priority:
Normal
Target version:
ruby -v:
ruby 1.9.2dev (2009-12-22 trunk 26152) [i386-darwin9.8.0]
Backport:

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


Related issues

Related to Ruby master - Bug #2700: various behavior when reopening File twiceRejectedActions
Related to Ruby master - Bug #2747: io.dup doesn't handle pos properlyRejected02/15/2010Actions

History

#1

Updated by mame (Yusuke Endoh) over 9 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

#2

Updated by kosaki (Motohiro KOSAKI) over 9 years ago

=begin
2010年2月11日15:24 Yusuke Endoh redmine@ruby-lang.org:

チケット #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  #=> 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 してしまう
方が混乱しなくてすむと思います。

できればユースケースの議論の前に挙動が変わった理由を把握したかった

のですが、何がバグで何が仕様かわかりませんでした。

Linuxだと同等の以下のCプログラムが

#include

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

#3

Updated by mame (Yusuke Endoh) over 9 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

#4

Updated by mame (Yusuke Endoh) over 9 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

Also available in: Atom PDF