I was working on a DSL for some asynchronous programming stuff and I
realized it’d be really nice if a block could rescue an exception.
So I went into IRB to see if it works and got a parse error. I
suppose you need a begin… end block or a proper method to have a
rescue block right now.
I was wondering if there’s any reason why this is so? It’d seem
pretty natural to me that a block could have rescue/else/ensure
conditions since a method body can have them.
DÅ?a Nedeľa 12 Február 2006 20:39 Mark V. napÃsal:
end
end
Sure it works, but Daniel wants to reduce the syntax a bit AND exit
the loop if an exception is raised without having to specify that. I
like his suggestion.
–
R. Mark V.
Partner, Object Computing, Inc.
It would cause a little inconsistency with the curly brace form of
blocks.
Either the rescue clause would have to work only for the do / end form,
or
we’d be mixing braces and keywords in a single construct, which I
couldn’t
bear to look at.
end
Sure it works, but Daniel wants to reduce the syntax a bit AND exit
the loop if an exception is raised without having to specify that. I
like his suggestion.
Sorry, not sure what the issue is (I assume you mean rescue, not raise
there).
If a rescue appears after a statement, it only applies to that
statement. If a rescue appears as the first token on a line, it
applies to the enclosing block. I’m pretty sure that’s how it works
now.
If you’re talking about doing something like…
foo.each{|o| raise “Oh noes, it’s number 2!” if o == 2; rescue
Exception => e; puts e.to_s}
Dòa Nedeµa 12 Február 2006 22:46 Daniel N. napísal:
Sorry, not sure what the issue is (I assume you mean rescue, not raise
there).
If a rescue appears after a statement, it only applies to that
statement. If a rescue appears as the first token on a line, it
applies to the enclosing block. I’m pretty sure that’s how it works
now.
stuff, but I’m not an old-school C-programmer so I never had to deal
with it — unfortunately for me…)
Well, my knowledge is limited. Someone else can answer better.
But look at it from a common-sense standpoint. Exceptions aren’t
magic. Everything Ruby does can be done in assembly language, it’s
just more verbose.
I would think that exceptions, at the lowest level, work something
like:
if something_happened_here
goto the_place_where_exceptions_are_caught
So at the very least, catching exceptions means that you’re doing
some sort of comparison or conditional branch. And this is code
that doesn’t have to be run/generated unless you are catching
exceptions.
You’re going to get a performance hit setting up an exception trap this
way.
Time for some down-South edumucation. What kind of performance hit are
we talking about here? And why the hit at all?
(I seem to recall reading somewhere once upon a time about memory stack
stuff, but I’m not an old-school C-programmer so I never had to deal
with it — unfortunately for me…)
But look at it from a common-sense standpoint. Exceptions aren’t
some sort of comparison or conditional branch. And this is code
if this_is_true
goto where_we_do_stuff_when_this_is_true
Hmm. This is something I’ve read, and it’s in my brain somewhere, but I
don’t know it well enough to grok it yet.
Especially at midnight…
But your explanation gives me a better idea of what is happening, even
with my questions.
Well, I think the point is that there is some non-zero amount of
“invisible”
code inserted between each statement. In fact, at a higher level of
granularity
than the statement.
For example, if I say: x = a/(b/(c/d)) there are three possible
places that
a ZeroDivision exception (or whatever it’s called) might happen.
Mentally, I’m
envisioning if-statements sprinkled throughout the evaluation of the
expression.
But again, this is all naive talk.
Sure, but couldn’t the parser “flag” blocks that have the exception
handler and only provide support for those cases? I do not see why we
would have to pay the price on every block – of course you have the
over head when you use it.
So at the very least, catching exceptions means that you’re doing
some sort of comparison or conditional branch. And this is code
that doesn’t have to be run/generated unless you are catching
exceptions.
Yes. You get a setup/teardown of an exception handler for every
block. Right now class module and def have an implicit exception
handler built in. Adding a begin; rescue; end explicitly to blocks
gives you a very hefty penalty. That’s no guarantee of similarly bad
performance with an implicit exception handler, but it still won’t be
free.
I’ve very rarely found myself placing an exception handler directly
inside a block so I don’t think it would be worth it.
$ cat rescue.rb
require ‘benchmark’
N = 10_000_000
Benchmark.bmbm do |b|
b.report ‘begin’ do
N.times { begin; rescue; end }
end
b.report ‘no begin’ do
N.times { }
end
end
$ ruby -v rescue.rb
ruby 1.8.4 (2005-12-24) [powerpc-darwin8.4.0]
Rehearsal --------------------------------------------
begin 6.330000 0.060000 6.390000 ( 8.303914)
no begin 2.580000 0.010000 2.590000 ( 3.178967)
----------------------------------- total: 8.980000sec
user system total real
begin 6.320000 0.060000 6.380000 ( 8.597418)
no begin 2.570000 0.020000 2.590000 ( 3.526030)