From: 3han5chou7@... Date: 2018-02-14T03:28:49+00:00 Subject: [ruby-core:85539] [Ruby trunk Bug#14472] `File::open` closes the file too early when used with callcc Issue #14472 has been updated by blackenedgold (Sunrin SHIMURA). > You can do it by `File.open` without a block. I know that. Again, I'm not in trouble. > `callcc` rollbacks ensures. I understand it isn't a bug, but an expected behaviour. Then the question is why this behaviour? > If `callcc` weren't fire ensures, it's unpredictable when `f1` and `f2` will get closed. Why? Is firing when control reached to the end not sufficient? In scheme, closing port before reaching the end is [explicitly forbidden](https://bitbucket.org/cowan/r7rs/src/4c27517de187142ad2cf4bcd8cb9199ae1e48c09/spec/procs.tex?at=draft-10&fileviewer=file-view-default#procs.tex-3757:3761) In #9105 case, error was occurring because control reached the end twice and ensure was fired twice. I think it's natural In this case, error is occurring because ensure is fired even though control doesn't reach the end. I think it's unnatural. ---------------------------------------- Bug #14472: `File::open` closes the file too early when used with callcc https://bugs.ruby-lang.org/issues/14472#change-70329 * 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: