Ensure is as much about resource management as it is about always running
something:

```ruby
class File
  def self.open(*args)
    file = new(*args)
    file&.open
    if file && file.open? && block_given?
      begin
        yield file
      ensure
        file.close
      end
    end
  end
end
```

Your proposal for a conditional `ensure` breaks that expectation and
complicates the language.

It sounds like what you really want is something like:

```ruby
def foo
  normal_path
rescue exception
  exception_handling_clause
aborted :return, :throw
  abnormal_path
ensure
  always_path
end
```

I”Ēm completely against your proposal as stated, and neutral on a possible
new clause like `aborted`. I don”Ēt see the value.


On Sat, Jan 26, 2019 at 6:00 AM <samuel / oriontransfer.net> wrote:

> Issue #15567 has been updated by ioquatix (Samuel Williams).
>
>
> @eregon - thanks for your response.
>
> > Ensure should always be executed no matter the circumstances IMHO, so I
> don't like to make it conditional with extra syntax.
>
> This isn't about not executing ensure, but allowing user to handle
> situations like "returned normally" vs "non-standard flow control".
>
> > I think the workaround using a variable set after yield (success = true)
> is not too bad, and clear enough. And the performance would be fine in this
> case (i.e. there would be no overhead if the JIT profiles the branch and
> only one branch is taken, like TruffleRuby).
>
> Personally, I think it's ugly, and I also think it is inefficient. I also
> don't think it's clearly conveying what the user is trying to do.
>
> The problem is, people write code like this:
>
> ```
> begin
>   ..
> ensure
>   abnormal_path if $!
> end
> ```
>
> This actually wrong and fails in the case of `throw` wrapped in `catch` as
> given in the original examples.
>
> It's actually not clear from the code if this is what the user wanted or
> not. Because you can't express clearly what you are actually interested in.
>
> There should be no overhead when exiting normally in the following
> situation:
>
> ```
> begin
>   yield
> ensure when not return
>   return :abnormal
> end
> ```
>
> As soon as you write code like:
>
> ```
> begin
>   yield
>   success = true
> ensure
>   return :abnormal unless success
> end
> ```
>
> you guarantee that the code must pass through the ensure block. But your
> intention is, only execute this code if the code didn't return normally (or
> some other flow control).
>
> So, I don't think the argument about always executing ensure holds up -
> this isn't about changing the semantics of `ensure` but extending it to
> handle explicitly what people are already doing, albeit probably
> incorrectly and inefficiently.
>
> ----------------------------------------
> Feature #15567: Allow ensure to match specific situations
> https://bugs.ruby-lang.org/issues/15567#change-76524
>
> * Author: ioquatix (Samuel Williams)
> * Status: Open
> * Priority: Normal
> * Assignee: ioquatix (Samuel Williams)
> * Target version: 2.7
> ----------------------------------------
> 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>
>


-- 
Austin Ziegler  halostatue / gmail.com  austin / halostatue.ca
http://www.halostatue.ca/  http://twitter.com/halostatue
(supressed text/html)
Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>