Issue #15567 has been updated by jeremyevans0 (Jeremy Evans).


ioquatix (Samuel Williams) wrote:
> One more thing to bear in mind is that you can avoid this feature if you don't like it. Because it's for some very specific situations. It doesn't affect existing code in any way. But for situations like mine where I have a handful of use cases, and efficiency is a concern (to an extent) as well as readability and correctness, I would welcome such a feature. If you don't need it you won't be affected by it, but if you need it, there is actually no other practical solution in the language right now.

In the very rare cases where you want to treat a non-local, non-exception exit differently from a normal exit, as Eregon mentioned, there is a simple existing practical solution that is unlikely to be significantly less efficient:

~~~ruby
def doot
  ret = yield
  normal_exit = true
  ret
ensure                                                                                                                                                                                                              
  # Did the block return normally
  return "abnormal" if $! || !normal_exit
end
~~~

I think we should definitely not add syntax in an attempt to make it easier to treat a non-local, non-exception exit differently than a normal exit, as doing so is usually a mistake.

You may not consider the above approach a simple and practical solution.  However, considering you have already conceded that your proposal is for "very specific situations" and you only have "handful of use cases", even if you consider it neither simple nor practical, it's still easy and possible.  New syntax is not necessary to support what you want, and I do not think new syntax should be added for "very specific situations" with only a "handful of use cases" when it is already possible to get the behavior you want with existing syntax.

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

* Author: ioquatix (Samuel Williams)
* Status: Open
* Priority: Normal
* Assignee: ioquatix (Samuel Williams)
* Target version: 
----------------------------------------
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>