From: eregontp@... Date: 2021-06-02T16:59:28+00:00 Subject: [ruby-core:104149] [Ruby master Feature#15567] Allow ensure to match specific situations Issue #15567 has been updated by Eregon (Benoit Daloze). Thanks for the link. Is `throw` used for other things than `redirect`? If `redirect` would use a regular exception, and for instance pass `[]` as the backtrace, it would probably be as efficient, but then gives the possibility to differentiate for example with `rescue => e; e&.should_commit?` or so. `throw`/`catch` has AFAIK no way to communicate any information, so there is no way to know if the `throw` is meant as a convenience return like for `redirect` or as some kind of bailout which should not commit the transaction. It can't even be differentiated from return/break so it seems a bad idea to use `throw` in the first place. It feels weird that Timeout uses `throw` and not `raise`, and it seems counter-intuitive (everyone knows `Timeout.timeout {}` raises Timeout::Error, and exception, `throw` is unexpected) It also adds quite some complexity: https://github.com/ruby/timeout/blob/4893cde0eda321448a1a86487ac9b571f6c35727/lib/timeout.rb#L29-L50 Does anyone know what's the point of that? What I could find is https://github.com/ruby/timeout/commit/238c003c921e6e555760f8e96968562a622a99c4 and https://bugs.ruby-lang.org/issues/8730 IMHO `rescue Exception` without re-raise is always the bug. ---------------------------------------- Feature #15567: Allow ensure to match specific situations https://bugs.ruby-lang.org/issues/15567#change-92321 * 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: