Issue #15567 has been updated by Eregon (Benoit Daloze).


What's wrong with this, which works fine?
```ruby
def transaction
  begin
    puts "Begin Transaction"
    result = yield
    success = true
    result
  ensure
    if success
      puts "Commit Transaction"
    else
      puts "Abort Transaction"
    end
  end
end

catch(:ball) do
  transaction do
    throw :ball
  end
end
```
IMHO it's clear and explicit.
What we want to check here is ultimately if the block was successful (no error of any sort) and the local variable is pretty clear.
In fact, you might even want to allow the block to return `:abort` or so, and then it would simply be `if success && result != :abort`.

FWIW I think there are very few use cases where `throw`/`catch` are a good idea, but this applies to `break` and others.
Short answer: use `ensure` if you want to be sure something runs, `rescue` only captures `Exception`, as expected.

----------------------------------------
Feature #15567: Allow ensure to match specific situations
https://bugs.ruby-lang.org/issues/15567#change-92239

* Author: ioquatix (Samuel Williams)
* Status: Rejected
* Priority: Normal
* Assignee: ioquatix (Samuel Williams)
----------------------------------------
There are some situations where `rescue Exception` or `ensure` are not sufficient to correctly, efficiently and easily handle abnormal flow control.

Take the following program for example:

```
def doot
	yield
ensure
	# Did the function run to completion?
	return "abnormal" if $!
end

puts doot{throw :foo}
puts doot{raise "Boom"}
puts doot{"Hello World"}

catch(:foo) do
	puts doot{throw :foo}
end
```

Using `rescue Exception` is not sufficient as it is not invoked by `throw`.

Using `ensure` is inefficient because it's triggered every time, even though exceptional case might never happen or happen very infrequently.

I propose some way to limit the scope of the ensure block:

```
def doot
	yield
ensure when raise, throw
	return "abnormal"
end
```

The scope should be one (or more) of `raise`, `throw`, `return`, `next`, `break`, `redo`, `retry` (everything in `enum ruby_tag_type` except all except for `RUBY_TAG_FATAL`).

Additionally, it might be nice to support the inverted pattern, i.e.

```
def doot
	yield
ensure when not return
	return "abnormal"
end
```

Inverted patterns allow user to specify the behaviour without having problems if future scopes are introduced.

`return` in this case matches both explicit and implicit.




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