[#104740] [Ruby master Feature#18057] Introduce Array#average — ggmichaelgo@...

Issue #18057 has been reported by ggmichaelgo (Michael Go).

14 messages 2021/08/02

[#104774] [Ruby master Bug#18061] Execshield test: libruby.so.N.N.N: FAIL: property-note test because no .note.gnu.property section found — jaruga@...

Issue #18061 has been reported by jaruga (Jun Aruga).

48 messages 2021/08/04

[#104780] [Ruby master Bug#18062] Ruby with enabled LTO segfaults during build — v.ondruch@...

Issue #18062 has been reported by vo.x (Vit Ondruch).

30 messages 2021/08/05

[#104831] [Ruby master Bug#18066] Load did_you_mean eve/error_highlight even with --disable-gems — v.ondruch@...

Issue #18066 has been reported by vo.x (Vit Ondruch).

10 messages 2021/08/07

[#104851] [Ruby master Bug#18073] test/ruby/test_jit.rb: failures "error: invalid use of '__builtin_va_arg_pack ()'" on Ruby 2.7.4 on gcc 4.8.5 on RHEL7 — jaruga@...

Issue #18073 has been reported by jaruga (Jun Aruga).

14 messages 2021/08/09

[#104927] [Ruby master Bug#18077] Marshal.dump(closed_io) raises IOError instead of TypeError — "larskanis (Lars Kanis)" <noreply@...>

Issue #18077 has been reported by larskanis (Lars Kanis).

10 messages 2021/08/16

[#104960] [Ruby master Feature#18083] Capture error in ensure block. — "ioquatix (Samuel Williams)" <noreply@...>

Issue #18083 has been reported by ioquatix (Samuel Williams).

32 messages 2021/08/18

[#105021] [Ruby master Misc#18122] DevelopersMeeting20210916Japan — "mame (Yusuke Endoh)" <noreply@...>

Issue #18122 has been reported by mame (Yusuke Endoh).

12 messages 2021/08/20

[#105069] [Ruby master Bug#18133] LTO: TestGCCompact#test_ast_compacts segfaults on i686 — "vo.x (Vit Ondruch)" <noreply@...>

Issue #18133 has been reported by vo.x (Vit Ondruch).

25 messages 2021/08/25

[#105077] [Ruby master Feature#18136] take_while_after — "zverok (Victor Shepelev)" <noreply@...>

Issue #18136 has been reported by zverok (Victor Shepelev).

21 messages 2021/08/27

[ruby-core:105005] [Ruby master Feature#18083] Capture error in ensure block.

From: "ioquatix (Samuel Williams)" <noreply@...>
Date: 2021-08-19 09:57:40 UTC
List: ruby-core #105005
Issue #18083 has been updated by ioquatix (Samuel Williams).


@matz I agree with your general feeling completely. But it's too late: We already have "ugly and against the basic concept of ensure" in the form of `$!`. As demonstrated, people are checking `$!` and unfortunately, in general code, it is not safe to check `$!` in an `ensure` block because it might come from the parent scope (or some other scope). This puts us in a difficult situation.

I think the decision depends on whether you want to support or deprecate the usage of `$!`. Fundamentally, if you think that `ensure => error` is ugly, I believe you must agree `ensure ... if $!` is equally ugly.

## Support `$!`

If we want to support $!, I would propose that we make it safe, by limiting it to the current block. That means it's effectively reset on entering a `begin...ensure...end` block, so we prevent it carrying state from the parent scope (if any).

## Deprecate `$!`

If we want to deprecate $!, I would propose that we consider how we want engineers to approach the problem they are currently depending on `$!` for.

The most common use case is something like this:

```ruby
begin
  resource = acquire # get a resource from the pool or allocate one if pool is empty.
  yield resource
ensure
  if $!
    free(resource) # resource is broken, get rid of it.
  else
    release(resource) # resource is okay, return it to the pool.
  end
end
```

The proposal to use `else` is a good one, except it doesn't capture all flow controls:

```ruby
begin
  resource = acquire # get a resource from the pool or allocate one if pool is empty.
  yield resource
rescue Exception
  free(resource) # resource is broken, get rid of it.
else
  release(resource) # resource is okay, return it to the pool.
end
```

The problem with the above code, is there are some cases where you can exit the block and neither the rescue nor the else block are executed. It will result in a resource leak. Also, some people would argue that `rescue Exception` is wrong. So, can we make the above better? If we make `else` the same as "ensure without exception" then it would be sufficient, but right now it's not.

The next best alternative is something like this:

```ruby
begin
  resource = acquire # get a resource from the pool or allocate one if pool is empty.
  yield resource
rescue Exception => error
  free(resource) # resource is broken, get rid of it.
  raise
ensure
  unless error
    release(resource) # resource is okay, return it to the pool.
  end
end
```

So the fundamental problem we have is that we don't have any way to guarantee, AFAIK, on error execute this code, otherwise execute this other code, and it turns out that a lot of code needs this, essentially "ensure if no exception was raised" or "ensure if no rescue block was executed", or something similar.

By the way, your proposed solution also falls short:

~~~
catch(:finished) do
  begin
    throw :finished
    no_error = true
  ensure
    p :error_handling unless no_error
  end
end
~~~

Will execute `error_handling`. This is why it's a non-trivial problem. Everyone comes up with the wrong answer (including me). If you look at real code, you see these incorrect patterns repeated over and over.


----------------------------------------
Feature #18083: Capture error in ensure block.
https://bugs.ruby-lang.org/issues/18083#change-93405

* Author: ioquatix (Samuel Williams)
* Status: Open
* Priority: Normal
----------------------------------------
As discussed in https://bugs.ruby-lang.org/issues/15567 there are some tricky edge cases.

As a general model, something like the following would be incredibly useful:

``` ruby
begin
 ...
ensure => error
  pp "error occurred" if error
end
```

Currently you can get similar behaviour like this:

``` ruby
begin
  ...
rescue Exception => error
  raise
ensure
  pp "error occurred" if error
end
```

The limitation of this approach is it only works if you don't need any other `rescue` clause. Otherwise, it may not work as expected or require extra care. Also, Rubocop will complain about it.

Using `$!` can be buggy if you call some method from `rescue` or `ensure` clause, since it would be set already. It was discussed extensively in https://bugs.ruby-lang.org/issues/15567 if you want more details.



-- 
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>

In This Thread