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 `<main>'
~~~

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: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>