Rescuing blocks?

D

Daniel Nugent

Hey guys,

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.

Has this been discussed elsewhere?

Thanks,
 
D

David Vallner

D=C5=88a Nede=C4=BEa 12 Febru=C3=A1r 2006 19:26 Daniel Nugent nap=C3=ADsal:
Hey guys,

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.

Has this been discussed elsewhere?

Thanks,

I'm afraid I don't quite catch your drift. What do you mean by a block not=
=20
rescuing an exception? Some example code wouldn't hurt.

David Vallner
 
L

Lou Vanek

this works,

foo =3D [1, 2, 3]

foo.each do |o|
begin
raise "Oh noes, it's number 2!" if o =3D=3D 2
rescue Exception =3D> e
puts e.to_s
end
end


Daniel said:
Whoops, shoulda thought of that, a-doy.
=20
Okay, it's pretty simple, here's what I'd like to do (you can
extrapolate the rest of the syntax from the simple example):
=20
foo =3D [1, 2, 3]
=20
foo.each do |o|
raise "Oh noes, it's number 2!" if o =3D=3D 2
rescue Exception =3D> e
puts e.to_s
end
=20
And so on and so forth. It seems pretty natural to me.... I don't
think it breaks anything (least not off the top of my head)...
=20
Hey guys,

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.

Has this been discussed elsewhere?

Thanks,

I'm afraid I don't quite catch your drift. What do you mean by a block = not
rescuing an exception? Some example code wouldn't hurt.

David Vallner
=20
=20
=20[/QUOTE]
 
M

Mark Volkmann

this works,

foo =3D [1, 2, 3]

foo.each do |o|
begin
raise "Oh noes, it's number 2!" if o =3D=3D 2
rescue Exception =3D> e
puts e.to_s
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.
 
D

David Vallner

D=C5=88a Nede=C4=BEa 12 Febru=C3=A1r 2006 20:39 Mark Volkmann nap=C3=ADsal:
this works,

foo =3D [1, 2, 3]

foo.each do |o|
begin
raise "Oh noes, it's number 2!" if o =3D=3D 2
rescue Exception =3D> e
puts e.to_s
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.

It would cause a little inconsistency with the curly brace form of blocks.=
=20
Either the rescue clause would have to work only for the do / end form, or=
=20
we'd be mixing braces and keywords in a single construct, which I couldn't=
=20
bear to look at.

David Vallner
 
D

David Vallner

How would you parse the difference whether the raise applies to the whole=20
block, or just the previous statement?

David Vallner

D=F2a Nede=B5a 12 Febru=E1r 2006 21:43 Daniel Nugent nap=EDsal:
Is

foo.each {|o|
raise "Oh noes, it's number 2!" if o =3D=3D 2
rescue Exception =3D> e
puts e.to_s
}

really that hideous?

D=F2a Nede=B5a 12 Febru=E1r 2006 20:39 Mark Volkmann nap=EDsal:
this works,

foo =3D [1, 2, 3]

foo.each do |o|
begin
raise "Oh noes, it's number 2!" if o =3D=3D 2
rescue Exception =3D> e
puts e.to_s
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.

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 / e= nd
form, or we'd be mixing braces and keywords in a single construct, which
I couldn't bear to look at.

David Vallner
 
D

David Vallner

D=F2a Nede=B5a 12 Febru=E1r 2006 22:46 Daniel Nugent nap=EDsal:
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.

<dense>D'oh. Didn't know that one... </dense>


David Vallner
 
P

Patrick Hurley

T24gMi8xMi8wNiwgRGF2aWQgVmFsbG5lciA8ZGF2aWRAdmFsbG5lci5uZXQ+IHdyb3RlOgo+Cj4K
PiBE8mEgTmVkZbVhIDEyIEZlYnJ14XIgMjAwNiAyMjo0NiBEYW5pZWwgTnVnZW50IG5hcO1zYWw6
Cj4gPiBTb3JyeSwgbm90IHN1cmUgd2hhdCB0aGUgaXNzdWUgaXMgKEkgYXNzdW1lIHlvdSBtZWFu
IHJlc2N1ZSwgbm90IHJhaXNlCj4gPiB0aGVyZSkuCj4gPgo+ID4gSWYgYSByZXNjdWUgYXBwZWFy
cyBhZnRlciBhIHN0YXRlbWVudCwgaXQgb25seSBhcHBsaWVzIHRvIHRoYXQKPiA+IHN0YXRlbWVu
dC4gIElmIGEgcmVzY3VlIGFwcGVhcnMgYXMgdGhlIGZpcnN0IHRva2VuIG9uIGEgbGluZSwgaXQK
PiA+IGFwcGxpZXMgdG8gdGhlIGVuY2xvc2luZyBibG9jay4gIEknbSBwcmV0dHkgc3VyZSB0aGF0
J3MgaG93IGl0IHdvcmtzCj4gPiBub3cuCj4KPiA8ZGVuc2U+RCdvaC4gRGlkbid0IGtub3cgdGhh
dCBvbmUuLi4gPC9kZW5zZT4KPgo+Cj4gRGF2aWQgVmFsbG5lcgo+Cj4KCisxCg==
 
D

Daniel Nugent

U28sIG1heWJlIHRoaXMgY2FsbHMgZm9yIGEgUkNSPwoKSSBrbm93IGZvciBzdXJlIHRoYXQgSSdk
IGxpa2UgYmxvY2tzIHRvIGJlIHJlc2N1YWJsZS4KCk9uIDIvMTMvMDYsIFBhdHJpY2sgSHVybGV5
IDxwaHVybGV5QGdtYWlsLmNvbT4gd3JvdGU6Cj4gT24gMi8xMi8wNiwgRGF2aWQgVmFsbG5lciA8
ZGF2aWRAdmFsbG5lci5uZXQ+IHdyb3RlOgo+ID4KPiA+Cj4gPiBE8mEgTmVkZbVhIDEyIEZlYnJ1
4XIgMjAwNiAyMjo0NiBEYW5pZWwgTnVnZW50IG5hcO1zYWw6Cj4gPiA+IFNvcnJ5LCBub3Qgc3Vy
ZSB3aGF0IHRoZSBpc3N1ZSBpcyAoSSBhc3N1bWUgeW91IG1lYW4gcmVzY3VlLCBub3QgcmFpc2UK
PiA+ID4gdGhlcmUpLgo+ID4gPgo+ID4gPiBJZiBhIHJlc2N1ZSBhcHBlYXJzIGFmdGVyIGEgc3Rh
dGVtZW50LCBpdCBvbmx5IGFwcGxpZXMgdG8gdGhhdAo+ID4gPiBzdGF0ZW1lbnQuICBJZiBhIHJl
c2N1ZSBhcHBlYXJzIGFzIHRoZSBmaXJzdCB0b2tlbiBvbiBhIGxpbmUsIGl0Cj4gPiA+IGFwcGxp
ZXMgdG8gdGhlIGVuY2xvc2luZyBibG9jay4gIEknbSBwcmV0dHkgc3VyZSB0aGF0J3MgaG93IGl0
IHdvcmtzCj4gPiA+IG5vdy4KPiA+Cj4gPiA8ZGVuc2U+RCdvaC4gRGlkbid0IGtub3cgdGhhdCBv
bmUuLi4gPC9kZW5zZT4KPiA+Cj4gPgo+ID4gRGF2aWQgVmFsbG5lcgo+ID4KPiA+Cj4KPiArMQo+
CgoKLS0KLURhbiBOdWdlbnQK
 
E

Eric Hodel

Whoops, shoulda thought of that, a-doy.

Okay, it's pretty simple, here's what I'd like to do (you can
extrapolate the rest of the syntax from the simple example):

foo = [1, 2, 3]

foo.each do |o|
raise "Oh noes, it's number 2!" if o == 2
rescue Exception => e
puts e.to_s
end

And so on and so forth. It seems pretty natural to me.... I don't
think it breaks anything (least not off the top of my head)...

You're going to get a performance hit setting up an exception trap
this way.
 
D

Dave Cantrell

Eric said:
foo = [1, 2, 3]

foo.each do |o|
raise "Oh noes, it's number 2!" if o == 2
rescue Exception => e
puts e.to_s
end

And so on and so forth. It seems pretty natural to me.... I don't
think it breaks anything (least not off the top of my head)...

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...)

-dave
 
H

Hal Fulton

Dave said:
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...)

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.

Just my naive take.


Hal
 
D

Dave Cantrell

Hal said:
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.

Just my naive take.


Hal

That's kind of along the lines of what I was thinking, just better said.
But this makes me wonder:

(a) Worrying about the performance hit from comparison/conditional
branching leads to the question "is all branching in blocks bad?"
Obviously not.

(b) Couldn't you say that *any* conditional could be jumping out to
another section of code? i.e. not just exception handlers?

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.

Thanks!
-dave
 
H

Hal Fulton

Dave said:
That's kind of along the lines of what I was thinking, just better said.
But this makes me wonder:

(a) Worrying about the performance hit from comparison/conditional
branching leads to the question "is all branching in blocks bad?"
Obviously not.

(b) Couldn't you say that *any* conditional could be jumping out to
another section of code? i.e. not just exception handlers?

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.


Hal
 
E

Eric Hodel

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.

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)
 
P

Patrick Hurley

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.

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 =3D 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)

--
Eric Hodel - (e-mail address removed) - http://segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

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.

pth
 
L

Logan Capaldo

--Apple-Mail-2-662308326
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
charset=US-ASCII;
format=flowed


N.times { { } }

This is equivalent to N.times { Hash.new }


--Apple-Mail-2-662308326--
 
D

David Vallner

D=C5=88a Streda 15 Febru=C3=A1r 2006 20:03 Dave Cantrell nap=C3=ADsal:
On a lark, I did this, and was shocked at the result. Why the massive
difference in performance between "begin; end" within a block, and "{ }"
within a block?

Because it's a literal hash constructor, not a nested block?

On a slightly related note, the literal hash constructor is apparently fast=
er=20
than Hash.new. Good to know.

David Vallner
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,202
Messages
2,571,057
Members
47,664
Latest member
RoseannBow

Latest Threads

Top