Calling break in proc

Hello,

It looks like a recent change has been introduced to the 1.8 branch in
cvs and also to cvs HEAD that causes the following code to break:

···

hash = { 1 => ‘a’, 2 => ‘b’ }

callback = proc { break }

hash.each(&callback)

==> LocalJumpError: break from proc-closure

However, the following does still work:

hash.each { break }


The code works with ruby 1.8.1, but not with 1.8-cvs or 1.9.

Is this change intentional? If so, can someone recommend a better way
to exit early from a Proc object? The catch/throw approach doesn’t feel
very natural.

Thanks,
Brad

$ ~/ruby1.9/bin/ruby -v -e “p lambda{ return 1 }.call”
ruby 1.9.0 (2004-03-25) [i686-linux]
1

···

On Tue, Mar 30, 2004 at 04:02:54AM +0900, Brad Hilton wrote:

Is this change intentional? If so, can someone recommend a better way
to exit early from a Proc object? The catch/throw approach doesn’t feel
very natural.


Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

‘Ooohh… “FreeBSD is faster over loopback, when compared to Linux
over the wire”. Film at 11.’
– Linus Torvalds

Hi,

At Tue, 30 Mar 2004 04:02:54 +0900,
Brad Hilton wrote in [ruby-talk:96055]:

The code works with ruby 1.8.1, but not with 1.8-cvs or 1.9.

And works with latest 1.8 and 1.9 in cvs.

···


Nobu Nakada

Mauricio Fernández wrote:

···

On Tue, Mar 30, 2004 at 04:02:54AM +0900, Brad Hilton wrote:

Is this change intentional? If so, can someone recommend a better way
to exit early from a Proc object? The catch/throw approach doesn’t feel
very natural.

$ ~/ruby1.9/bin/ruby -v -e “p lambda{ return 1 }.call”
ruby 1.9.0 (2004-03-25) [i686-linux]
1

Just creating a proc {} or labmda {} doesn’t display the problem. You
need to pass it to an iterator it seems:

hash = { ‘a’ => 1, ‘b’ => 2 }
callback = proc { return }
hash.each(&callback)

==> return from proc-closure (LocalJumpError)

My app is still raising an error, so I’ve simplified things as much as
possible with a test script. The original example I provided does now
work with the latest cvs, but the following does not:

···

nobu.nokada@softhome.net wrote:

Hi,

At Tue, 30 Mar 2004 04:02:54 +0900,
Brad Hilton wrote in [ruby-talk:96055]:

The code works with ruby 1.8.1, but not with 1.8-cvs or 1.9.

And works with latest 1.8 and 1.9 in cvs.


class DelayedFetcher
def initialize(&block)
@block = block
@rows = nil
end

def load_data
return if @rows
@rows =
@block.call(proc { |hash| @rows << hash })
end # load_data

def call
load_data
@rows.each { |row|
yield(row)
}
end
end # DelayedFetcher

create an object that lazily loads some data

obj = DelayedFetcher.new { |block|
10.times do |i|
block.call({ ‘i’ => i })
end
}

data_handler = proc { |hash|
p hash
break if hash[‘i’] == 5
}

obj.call(&data_handler)


I hope this helps to track down the problem.

Thanks,
Brad

I found a simpler example that exposes this strange proc/break problem.
There are some weird things going on here. If I comment out the line
in initialize(), things work. If I take out the call to p() in
initialize(), things work. If I pass a block of code directly in the
end of the script instead of creating a proc object (see code below),
things work. Can anyone shed some light on what is happening here?

Thanks,
-Brad

···

nobu.nokada@softhome.net wrote:

Hi,

At Tue, 30 Mar 2004 04:02:54 +0900,
Brad Hilton wrote in [ruby-talk:96055]:

The code works with ruby 1.8.1, but not with 1.8-cvs or 1.9.

And works with latest 1.8 and 1.9 in cvs.


class DelayedFetcher
def initialize
# comment this out to makes things work!?!
1.times { |i| p i }
end # initialize

def fetch(&block)
rows =
10.times { |num|
rows << { ‘i’ => num }
}
rows.each(&block)
end
end # DelayedFetcher

create an object that lazily loads some data

obj = DelayedFetcher.new

data_loader = proc { |hash|
p hash
break if hash[‘i’] == 5
}

this produces an error…

obj.fetch(&data_loader)

this works…

obj.fetch { |hash|
p hash
break if hash[‘i’] == 5
}

Hi,

I found a simpler example that exposes this strange proc/break problem.

The point is the break destination.

data_loader = proc { |hash|
p hash
break if hash[‘i’] == 5
}

this produces an error…

obj.fetch(&data_loader)

The destination of a break in the data_loader is the continuation to
the “proc”, which is already passed through at the point of
“obj.fetch”. Use catch/throw for dynamic exit.

						matz.
···

In message “Re: calling break in proc” on 04/04/02, Brad Hilton bhilton@vpop.net writes:

Yukihiro Matsumoto wrote:

Hi,

I found a simpler example that exposes this strange proc/break problem.

The point is the break destination.

data_loader = proc { |hash|
p hash
break if hash[‘i’] == 5
}

this produces an error…

obj.fetch(&data_loader)

The destination of a break in the data_loader is the continuation to
the “proc”, which is already passed through at the point of
“obj.fetch”. Use catch/throw for dynamic exit.

Thanks for the explanation - it makes sense. What surprises me is that
this code worked for 1.8.1, and still works of you remove the
initialize() function in my example code. That made me think there
might be a bug lurking somewhere… Ie, why would changing the
initialize function of my example class affect the behavior of a
break-point in a proc object?

-Brad

···

In message “Re: calling break in proc” > on 04/04/02, Brad Hilton bhilton@vpop.net writes:

Hi,

···

In message “Re: calling break in proc” on 04/04/02, Brad Hilton bhilton@vpop.net writes:

Thanks for the explanation - it makes sense. What surprises me is that
this code worked for 1.8.1, and still works of you remove the
initialize() function in my example code. That made me think there
might be a bug lurking somewhere… Ie, why would changing the
initialize function of my example class affect the behavior of a
break-point in a proc object?

Oops, there must be somewhere. Let me see.

						matz.