Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is the value of a begin block determined?

According to The Ruby Programming Language p.164.

If a begin statement doesn't propagate an exception, then the value of the statement is the value of the last expression evaluated in the begin, rescue or else clauses.

But I found this behavior consistent with the begin block together with else clause and ensure clause.

Here is the example code:

def fact (n)
  raise "bad argument" if n.to_i < 1
end

value = begin
  fact (1)
rescue RuntimeError => e
  p e.message
else
  p "I am in the else statement"
ensure
  p "I will be always executed"
  p "The END of begin block"
end

p value

The output is:

"I am in the else statement"
"I will be always executed"
"The END of begin block"
"I am in the else statement"
[Finished]

The value is evaluated to the else clause. This is inconsistent behavior as the ensure clause is the last statement executed.

Could someone explain what's happening within the begin block?

like image 921
steveyang Avatar asked Oct 09 '22 10:10

steveyang


1 Answers

I'd interpret the goal of the begin/rescue/else/end block as:

  • Execute the code in the begin section, and then the code in the else section.
  • If something goes wrong in the begin section, execute the rescue section instead of the else section.

So either the rescue section or the else section will be executed after trying the begin section; so it makes sense that one of them will be used as the whole block's value.

It's simply a side effect that the ensure section will always be executed.

val = begin
  p "first"; "first"
rescue => e
  p "fail"; "fail"
else
  p "else"; "else"
ensure
  p "ensure"; "ensure"
end

val # => "else"
# >> "first"
# >> "else"
# >> "ensure"

But:

val = begin
  p "first"; "first"
  raise
rescue => e
  p "fail"; "fail"
else
  p "else"; "else"
ensure
  p "ensure"; "ensure"
end

val # => "fail"
# >> "first"
# >> "fail"
# >> "ensure"
like image 188
jtbandes Avatar answered Oct 12 '22 11:10

jtbandes