From: 3han5chou7@... Date: 2018-02-14T04:12:49+00:00 Subject: [ruby-core:85540] [Ruby trunk Bug#14472] `File::open` closes the file too early when used with callcc Issue #14472 has been updated by blackenedgold (Sunrin SHIMURA). I used raw continuations for the simplicity of explanation but I found it was a bit confusing (and I was also confused). > ... code above must be the same as code below, which works fine: It was wrong. and > You can do it by `File.open` without a block. is absolutely correct. I wrote wrong code. I intended to write code with [delimited continuations](http://d.hatena.ne.jp/ku-ma-me/20080417/p1) like below. ~~~ ruby require 'continuation' def shift callcc {|c1| $ctn.(yield(proc {|v| callcc {|c2| $ctn = c2; c1.(v) } })) } end def reset callcc {|c| $ctn = c; v = yield; $ctn.(v) } end reset do f1 = shift {|k| File::open("test1", 'w') {|f| k.(f)}} f1.write("hello") end ~~~ *This* is exactly the same as ~~~ ruby File::open("test1", 'w') {|f1| f1.write("hello")} ~~~ including file is closed after the write is done. ---------------------------------------- Bug #14472: `File::open` closes the file too early when used with callcc https://bugs.ruby-lang.org/issues/14472#change-70330 * Author: blackenedgold (Sunrin SHIMURA) * Status: Rejected * Priority: Normal * Assignee: * Target version: * ruby -v: ruby 2.3.3p222 (2016-11-21) [x86_64-linux-gnu] * Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN ---------------------------------------- First of all, I know `callcc` is deprecated feature and I'm not in trouble with this bug. I was just curious and happened to find this bug. # Bug Description This code throws an IOError, but expected to exit normally: ~~~ ruby require 'continuation' f1 = callcc {|k| File::open("test1", 'w') {|f| k.(f)}} f1.write("hello") ~~~ ~~~ $ ruby openfile_cont.rb /usr/lib/x86_64-linux-gnu/ruby/2.3.0/continuation.so: warning: callcc is obsolete; use Fiber instead openfile_cont.rb:14:in `write': closed stream (IOError) from openfile_cont.rb:14:in `
' ~~~ I think this is a bug because the code above must be the same as code below, which works fine: ~~~ ruby File::open("test1", 'w') {|f1| f1.write("hello")} ~~~ In fact, an equivalent scheme code works fine: ~~~scheme (let* ((f1 (call/cc (lambda (k) (call-with-output-file "test1" k))))) (display "hello" f1)) ~~~ ~~~ $ gosh openfile_cont.scm $ cat test1 hello ~~~ # Importance Again, I'm not in trouble with this bug. The bugging code is useful to rewrite nested `open` blocks to flat style like this: ~~~ ruby File::open("test1", 'w') do |f1| File::open("test2", 'w') do |f2| f1.write("hello") f2.write("hello") end end ~~~ ~~~ ruby f1 = callcc {|k| File::open("test1", 'w') {|f| k.(f)}} f2 = callcc {|k| File::open("test2", 'w') {|f| k.(f)}} f1.write("hello") f2.write("hello") ~~~ Or, even code that cannot be written with nested `open`s can be written with callcc: ~~~ ruby ["test1", "test2", "test3"].map{|path| callcc {|k| File::open(path, 'w') {|f| k.(f)}}}.each do |f| f.write("hello") end ~~~ Again, equivalent scheme code works fine: ~~~ (let ((paths '("test1" "test2" "test3"))) (let ((ports (map (lambda (path) (call/cc (lambda (k) (call-with-output-file path k)))) paths))) (dolist (port ports) (display "hello" port)))) ~~~ -- https://bugs.ruby-lang.org/ Unsubscribe: