Else inside rescue is useless?

http://www.awprofessional.com/bookstore/product.asp?isbn=0672328844&rl=1

The “The ruby way” book said

but actually, I found the “else” clause is only executed when there is
no exception been thrown,such as :


begin
puts “do something”
rescue NameError
puts “name error #{$!}”
else
puts “else #{$!}”
end

the result is


do something
else

so the “else” clause is useless because we can simply put the content
of “else” caluse to the last line in the “begin” block before the first
“rescue”

Am I wrong or the book is wrong?

my ruby version is
ruby 1.8.4 (2005-12-24) [i686-linux]

exactly, the else is in the rescue which means an exception has been
thrown. if it doesn;t match any of the exceptions you’ve declared as
being important to catching, and you include an else, the else wiill
catch what you don;t want.

no?!

cap [email protected] wrote:
http://www.awprofessional.com/bookstore/product.asp?isbn=0672328844&rl=1

The “The ruby way” book said

but actually, I found the “else” clause is only executed when there is
no exception been thrown,such as :


begin
puts “do something”
rescue NameError
puts “name error #{$!}”
else
puts “else #{$!}”
end

the result is


do something
else

so the “else” clause is useless because we can simply put the content
of “else” caluse to the last line in the “begin” block before the first
“rescue”

Am I wrong or the book is wrong?

my ruby version is
ruby 1.8.4 (2005-12-24) [i686-linux]

Hi –

On Mon, 11 Dec 2006, Anthony G. wrote:

exactly, the else is in the rescue which means an exception has been
thrown. if it doesn;t match any of the exceptions you’ve declared as
being important to catching, and you include an else, the else wiill
catch what you don;t want.

no?!

No; I think what you need is just a blank ‘rescue’, not else:

begin
puts “do something”
raise ZeroDivisionError
rescue NameError
puts “name error #{$!}”
rescue
puts “else #{$!}”
end

Output:

do something
else ZeroDivisionError

An else clause will run if there’s no exception at all.

I don’t have my Ruby Way on me but if it says else I think it should
say rescue.

David

On 12/11/06, cap [email protected] wrote:

Error-prone code…

but actually, I found the “else” clause is only executed when there is

“rescue”

Am I wrong or the book is wrong?

my ruby version is
ruby 1.8.4 (2005-12-24) [i686-linux]

From the Rubinius test suite:
@count = 1
begin
p @count
raise ArgumentError, ‘just kidding’ unless @count > 3
rescue Exception => e
@count += 1
retry
else
p 7
ensure
p 8
end

this prints:
1
2
3
4
7
8

‘else’ only runs if no exception was raised.

On 11.12.2006 13:17, cap wrote:

Error-prone code…

rescue Type1

rescue Type2

else

Other exceptions…

end

[/quote]

This is plain wrong - at least in 1.8.5. The Pickaxe says the “else”
clause is executed if there was no exception. To catch any exception
you would have to replace the “else” with “rescue Exception => e” as
David indicated. However, there’s a glitch (read on).

end
of “else” caluse to the last line in the “begin” block before the first
“rescue”

Am I wrong or the book is wrong?

I think the book is wrong - and there is also a difference between the
Pickaxe and the interpreter implementation (unfortunately). Try this
code:

def foo(x)
begin
puts “x=#{x}”

 case x
   when 0
     puts "returning"
     return
   when 1
     raise "Some error"
   when 2
     raise NameError, "wrong name"
   when 3
     break "broken"
   else
     puts "do something"
 end

 puts "unsafe else"

rescue NameError
puts “name error: #{$!}”
else
puts “else”
ensure
puts “leaving!”
end
end

5.times do |i|
begin
foo i
rescue Exception => e
puts “Exception: #{e}”
end
end

With my 1.8.5 I see:

x=0
returning
leaving!
x=1
leaving!
Exception: Some error
x=2
name error: wrong name
leaving!
x=3
leaving!
Exception: unexpected break
x=4
do something
unsafe else
else
leaving!

What bugs me is that the “else” clause is not executed if it is left via
a “return”. Taking the Pickaxe 2nd edition pg. 362 literally (“If an
else clause is present, its body is executed if no exceptions were
raised in code.”) it would have to be executed in that case, too. So,
if the interpreter would behave as stated in the book, there was
actually a difference between the code at the end of the block and the
code inside the else clause.

Even in the current situation (where there seems to be no semantically
difference) putting code into the else clause instead of the end of the
block might have an advantage documentation wise.

Matz, can you clarify whether this is a bug in the interpreter or
whether the Pickaxe is wrong (or incomplete) here?

Kind regards

robert

On Dec 11, 2006, at 8:55 AM, Robert K. wrote:

  when 2

else
puts “Exception: #{e}”
Exception: Some error
leaving!

What bugs me is that the “else” clause is not executed if it is
left via a “return”. Taking the Pickaxe 2nd edition pg. 362
literally (“If an else clause is present, its body is executed if
no exceptions were raised in code.”) it would have to be executed
in that case, too. So, if the interpreter would behave as stated
in the book, there was actually a difference between the code at
the end of the block and the code inside the else clause.

I would be horrified if the were executed after a –
is not . The Pickaxe book should be probably say: “If
an else clause is present, its body is executed if no exceptions were
raised and no exit was made in code .” In fact, I just submitted an
erratum to this effect on the Pragmatic Programmer site.

Even in the current situation (where there seems to be no
semantically difference) putting code into the else clause instead
of the end of the block might have an advantage documentation wise.

Also from Pickaxe: “Exceptions raised during the execution of the
else clause are not captured by rescue clauses in the same block as
the else.” That seems to be a semantic difference.

Regards, Morton

yeha, yeah, yeah. my mistake.

am new to ruby but now remember that the else is only run if no
exceptions occur in the main body. bit of revision there :wink:

[email protected] wrote: Hi –

On Mon, 11 Dec 2006, Anthony G. wrote:

exactly, the else is in the rescue which means an exception has been
thrown. if it doesn;t match any of the exceptions you’ve declared as
being important to catching, and you include an else, the else wiill
catch what you don;t want.

no?!

No; I think what you need is just a blank ‘rescue’, not else:

begin
puts “do something”
raise ZeroDivisionError
rescue NameError
puts “name error #{$!}”
rescue
puts “else #{$!}”
end

Output:

do something
else ZeroDivisionError

An else clause will run if there’s no exception at all.

I don’t have my Ruby Way on me but if it says else I think it should
say rescue.

David


Q. What’s a good holiday present for the serious Rails developer?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
aka The Ruby book for Rails developers!
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

On Dec 11, 2006, at 7:55 AM, Robert K. wrote:

What bugs me is that the “else” clause is not executed if it is
left via a “return”. Taking the Pickaxe 2nd edition pg. 362
literally (“If an else clause is present, its body is executed if
no exceptions were raised in code.”) it would have to be executed
in that case, too. So, if the interpreter would behave as stated
in the book, there was actually a difference between the code at
the end of the block and the code inside the else clause.

Why would you expect the else clause to be executed if a return is
executed? That seems counter-intuitive to me.

Cheers

Dave

On 12/12/06, Robert K. [email protected] wrote:

Even in the current situation (where there seems to be no semantically
difference) putting code into the else clause instead of the end of the
block might have an advantage documentation wise.

If I’m understanding you correctly, there is a difference between:

begin
f
g
rescue E
end

and

begin
f
rescue E
else
g
end

and that is that any E’s raised in #g won’t be rescued in the latter.

On 12/12/06, Robert K. [email protected] wrote:

actually a difference between the code at the end of the block and the
I can’t remember ever having used this type of “else” clause so far so I
am pretty nonreligious about it. Although I can imagine a situation
where I would want to make sure some cleanup code is executed only when
there was no error in the block - and this includes leaving via
“return”.

and that is what ensure is for, right?
I guess the book is wrong and Matz is right ;), well my POV

Of course you can argue that leaving via “return” is a non

standard way to leave the block… As I said, I am pretty relaxed here.
I just think this needs some clarification - either way or the other.

Kind regards

    robert

Likewise


“The real romance is out ahead and yet to come. The computer revolution
hasn’t started yet. Don’t be misled by the enormous flow of money into
bad
defacto standards for unsophisticated buyers using poor adaptations of
incomplete ideas.”

  • Alan Kay

On Dec 12, 2006, at 4:10 AM, Robert K. wrote:

I have low expectations with regard to the “else” clause but the
book clearly states that it is executed if there was no exception -
that includes the case where the block is left via a “return”.
Behavior and description simply are not in sync, that’s my point.

Interesting: I’d honestly never have thought of that interpretation.
I guess in my mind, the semantics of return take precedence over most
other semantics, and I explicitly note the times where that’s not the
case. Thanks for pointing out an alternative.

Do you feel I should also document the other places when a return
could be issued? For example, in the description of a while loop, I
say “executes body zero or more times as long as boolean-expression
is true.” Should I add “or a return is executed or an exception is
thrown” to this and similar descriptions?

I kind of feel that this would clutter the descriptions, and that
most readers would make the assumption that return and exceptions
would break the flow. Is that an incorrect assumption?

Regards

Dave

On 12/12/06, Dave T. [email protected] wrote:

Interesting: I’d honestly never have thought of that interpretation.
I kind of feel that this would clutter the descriptions, and that
most readers would make the assumption that return and exceptions
would break the flow. Is that an incorrect assumption?

Maybe the assumption is wrong in some, maybe even many cases, but I
believe
you should keep this one as simple as possible, at this very point.
While explaining “while” you might not want to confuse newbies, and more
advanced readers might satisfy your assumption more likely anyway.

The structurally more complicated stuff like raise, ensure and do not
forget
nonlocal jumps (aka continuations) should be explained elsewhere and I
believe it is exactly at that elsewhere point where one might explain
the
impacts on the more basic constructs.

This is just a great piece of work and I think it is about perfect as it
is
now, well maybe I should read it after all :wink:

Regards

Dave

Robert (D not K)


“The real romance is out ahead and yet to come. The computer revolution
hasn’t started yet. Don’t be misled by the enormous flow of money into
bad
defacto standards for unsophisticated buyers using poor adaptations of
incomplete ideas.”

  • Alan Kay

On 12.12.2006 00:15, Dave T. wrote:

Why would you expect the else clause to be executed if a return is
executed? That seems counter-intuitive to me.

I have low expectations with regard to the “else” clause but the book
clearly states that it is executed if there was no exception - that
includes the case where the block is left via a “return”. Behavior and
description simply are not in sync, that’s my point.

I can’t remember ever having used this type of “else” clause so far so I
am pretty nonreligious about it. Although I can imagine a situation
where I would want to make sure some cleanup code is executed only when
there was no error in the block - and this includes leaving via
“return”. Of course you can argue that leaving via “return” is a non
standard way to leave the block… As I said, I am pretty relaxed here.
I just think this needs some clarification - either way or the other.

Kind regards

robert

On 12.12.2006 14:31, Dave T. wrote:

other semantics, and I explicitly note the times where that’s not the
case. Thanks for pointing out an alternative.

Dave, you’re welcome! I was probably in formal mode when reading that,
although I believe the situation here is a tad different from the
“while” loop case:

Do you feel I should also document the other places when a return could
be issued? For example, in the description of a while loop, I say
“executes body zero or more times as long as boolean-expression is
true.” Should I add “or a return is executed or an exception is thrown”
to this and similar descriptions?

Maybe just “… or the body of the loop is left via other control flow
statements”. You could even add a footnote which enumerates them. :slight_smile:

I kind of feel that this would clutter the descriptions, and that most
readers would make the assumption that return and exceptions would break
the flow. Is that an incorrect assumption?

I agree about cluttering and I think a change is not needed in this
cases - in other words, I believe it’s not an incorrect assumption. :slight_smile:

I think the case with “else” clause after “rescue” clauses is a bit
different because control flow is not explicit like with loops. It is
immediately clear that “break”, “return”, “raise” and “throw” will
instantly leave the loop (is it?). However, with “rescue - else” we are
talking about less explicit control flow and so maybe a more explicit
description is helpful here.

As I said, it’s probably a corner case and I have no idea how often this
“else” is actually used in applications. I for my part cannot remember
ever having used it - apart from the research for this thread.

It’s a totally different question whether the behavior of the
interpreter should change so code in “else” clause is executed even for
a “return”. There might be arguments in favor and against it. Maybe
Matz can shed some light about the reasoning why it is the way it is.

Kind regards

robert

Hi –

On Tue, 12 Dec 2006, Dave T. wrote:

in my mind, the semantics of return take precedence over most other
readers would make the assumption that return and exceptions would break the
flow. Is that an incorrect assumption?

No, I think it’s correct. I consider “executes body” to expand
automatically to “executes body unless execution is stopped, which can
always happen in various ways no matter what else is going on”.

I think the reason the question arose in the particular case of
begin/rescue/else/ensure… is that it involves the role of what to me
is a somewhat elusive clause (the else) right in the middle of a
construct where the control flow is already relatively complex.

David

Hi –

On Tue, 12 Dec 2006, Robert K. wrote:

guess in my mind, the semantics of return take precedence over most other
add “or a return is executed or an exception is thrown” to this and similar
descriptions?

Maybe just “… or the body of the loop is left via other control flow
statements”. You could even add a footnote which enumerates them. :slight_smile:

I don’t think that’s needed. Executing a body of code means executing
all the instructions in it, and it’s already known that the
instruction set includes things that affect flow control. So unless
those things are specifically excluded in a given context, I would
assume they are available.

David

Robert K. wrote:

I have low expectations with regard to the “else” clause but the book
clearly states that it is executed if there was no exception - that
includes the case where the block is left via a “return”. Behavior and
description simply are not in sync, that’s my point.

Dave T. replied:

Interesting: I’d honestly never have thought of that interpretation.
[…]
Do you feel I should also document the other places when a return could be
issued? For example, in the description of a while loop, I say “executes body
zero or more times as long as boolean-expression is true.” Should I add “or
a return is executed or an exception is thrown” to this and similar
descriptions?

I kind of feel that this would clutter the descriptions, and that most
readers would make the assumption that return and exceptions would break the
flow. Is that an incorrect assumption?

I think detailing every condition under which else would not get called
is
overdoing it a bit.

Instead of listing the conditions under which the else might not be
reached; how about instead of writing “The body of an else clause is
executed only if no exceptions are raised by the main body of code.”
You’d
write “The body of an else clause is executed only if the end of the
main
body of code is reached without causing any exceptions”. This to me
would
sound more clear - a return statement in the main block would prevent
the
end of the main body of code to be reached.

So, the difference is just that I can use the else block to insert code
that will run before the ensure (in your book example before the ensured
file.close) but outside of the rescue blocks (i.e. code in the else
block
CAN throw an exception which will not be handled in the current
begin/rescue block… (Whether this is useful or not, is another
issue)…

     def testme()
       begin
         begin
           puts "foo"
           #return(1);
      puts "raising error"
           puts "bar"
         rescue
           puts "inner rescue block"
         else
           raise ArgumentError.new("blah");
         ensure
           puts "ensured"
         end

       rescue
         puts "outer rescue block"
       end
     end

     testme();

will print

foo
bar
raising error
ensured
outer rescue block

If I were to uncomment the return(1), it would print

foo
ensured

Benedikt

ALLIANCE, n. In international politics, the union of two thieves who
have their hands so deeply inserted in each other’s pockets that
they cannot separately plunder a third.
(Ambrose Bierce, The Devil’s Dictionary)

On 12/12/06, Benedikt H. [email protected] wrote:

p 7

CAN raise unchecked exceptions.

Do you feel like that’s an implementation quirk of Ruby, or something
deliberate?
In other words, this code…

@count = 0
begin
@count += 1
raise RuntimeError.new(“Ha Ha!”) if @count == 1
rescue Exception
puts “hello from rescue”
retry
else
puts “else”
raise RuntimeError.new(“Boom”) if @count == 2
end

Is it part of ruby’s ‘spec’ that the ‘rescue’ block only be executed
once, in the above code?

On Tue, 12 Dec 2006, Wilson B. wrote:

ensure
p 8
end

[…]

‘else’ only runs if no exception was raised.

Yes, else only runs if no exception was raised; and it will run BEFORE
the
ensure block. BUT unlike code in the main code block (begin…rescue) it
CAN raise unchecked exceptions.

Benedikt

ALLIANCE, n. In international politics, the union of two thieves who
have their hands so deeply inserted in each other’s pockets that
they cannot separately plunder a third.
(Ambrose Bierce, The Devil’s Dictionary)

‘else’ only runs if no exception was raised.

Yes, else only runs if no exception was raised; and it will run BEFORE the
ensure block. BUT unlike code in the main code block (begin…rescue) it
CAN raise unchecked exceptions.

retry
else
puts “else”
raise RuntimeError.new(“Boom”) if @count == 2
end

Is it part of ruby’s ‘spec’ that the ‘rescue’ block only be executed
once, in the above code?

It sounds like it is deliberate - otherwise, why introducing the else
block at all? That’s the only thing that else does.

Also, when you say “rescue block only be executed once in the above
code”,
if you took the first raise (“Ha Ha!”) away - it would not trigger the
rescue at all. This is apparently, why ‘else’ is positioned AFTER
‘rescue’ in the execution order. Once you’re past the rescue block,
there
is no rescue to jump back to. i.e. if you want to rescue from an
exception
in the else block, you’d need to do it in a separate begin…rescue…end
block wrapping around the begin…rescue…else…end construct you are
using.

Benedikt

ALLIANCE, n. In international politics, the union of two thieves who
have their hands so deeply inserted in each other’s pockets that
they cannot separately plunder a third.
(Ambrose Bierce, The Devil’s Dictionary)