Subtle bug with catch/throw. Am I missing something?

P

Patrick Li

Hi,
I'm having trouble locating this bug that I'm having. I think it's
because I don't completely understand Ruby's throw/catch mechanism.

I'm trying to write a simple example that demonstrates the same problem,
but I can't track down the bug.

Here's my code: Is there any subtleties that may cause throw/catch to
not behave as expected?

def idle(engine,key)
catch:)exit) do <-- Catch :exit
while engine.nextFrame(key)
engine.drawFrame do
drawInContext(@img, 0, 0, 1)
end

@enterEvent.listen do
@state = method:)active)
puts "player entered"
throw :exit <-- Throw :exit
end
end
end
end

Gives me: "in `throw': uncaught throw `exit' (NameError)"

And what's really strange is, the problem goes away after putting in a
print statement.


def idle(engine,key)
catch:)exit) do <-- Catch :exit
while engine.nextFrame(key)
engine.drawFrame do
drawInContext(@img, 0, 0, 1)
end

@enterEvent.listen do
@state = method:)active)
puts "player entered"
throw :exit <-- Throw :exit
end
end
end

puts "end" <-- This line causes the problem to go away.
end

Thanks a lot for your help. Any place to start looking would be really
helpful. I'm fresh out of ideas.
-Patrick

I'm using Ruby 1.8.6 on Windows.
 
T

Thomas B.

Patrick said:
@enterEvent.listen do
@state = method:)active)
puts "player entered"
throw :exit <-- Throw :exit
end

What does this @enterEvent.listen do? If it saves the block passed to it
and terminates, and the block gets executed later, when the main control
is already out of your idle method, you will get the error. Here's
example of an error-producing code to illustrate what I say:

class K
def listen(&b)
@b=b
end
def idle
catch:)a){listen{throw:)a)}}
end
def call
@b.call
end
end
k=K::new
k.idle
k.call

It causes an error even though throw is inside catch, when we look at
the code.

TPR.
 
J

Joel VanderWerf

Patrick said:
Hi,
I'm having trouble locating this bug that I'm having. I think it's
because I don't completely understand Ruby's throw/catch mechanism.

I'm trying to write a simple example that demonstrates the same problem,
but I can't track down the bug.

Here's my code: Is there any subtleties that may cause throw/catch to
not behave as expected?

def idle(engine,key)
catch:)exit) do <-- Catch :exit
while engine.nextFrame(key)
engine.drawFrame do
drawInContext(@img, 0, 0, 1)
end

@enterEvent.listen do
@state = method:)active)
puts "player entered"
throw :exit <-- Throw :exit
end
end
end
end

Gives me: "in `throw': uncaught throw `exit' (NameError)"

I'm guessing that the problem is that the listen block has been saved
away and is no longer above the #catch on the stack. Here's a simpler
example:

def listen
catch:)exit) do
@listeners << proc {throw :exit}
end
end

@listeners = []
listen
@listeners[0].call

This produces the same error message.
 
P

Patrick Li

Ah I see.
Thank you. That would have taken me forever to find.

Is there a way around this? Or is this basically a design issue?
 
J

John Pritchard-williams

Patrick,

Just a guess: can you clarify the 'while' loop with a 'do' I wonder?

Just wondering whether the interpreter is getting confused here - and
the extra 'puts' is somehow clarifying the situation for it ?

Cheers

John

ie:

while engine.nextFrame(key) do
...
 
T

Thomas B.

Patrick said:
Ah I see.
Thank you. That would have taken me forever to find.

Is there a way around this? Or is this basically a design issue?

It's a design issue, if it is the case, because at the time the :exit is
thrown, you're already out of idle(), so catching it there is definitely
not what you intended. Probably you should catch the exception somewhere
higher on the stack, from the method that, I guess, calls idle in a
loop, or even higher.

TPR.
 
P

Patrick Li

Thanks for your responses.

I think I understand now. I was just using the catch as a lazy way to
break out of the loop. I can just use a loop flag instead then.

I still don't know why the "puts" statement avoids the error. The "do"
after the "while" doesn't help either.
 
J

John Pritchard-williams

Patrick said:
Thanks for your responses.

I think I understand now. I was just using the catch as a lazy way to
break out of the loop. I can just use a loop flag instead then.

I still don't know why the "puts" statement avoids the error. The "do"
after the "while" doesn't help either.

Patrick,

Again total guesswork , but based on the other posts from people who
actually know what they are talking about... - sounds like the symbol
':exit' is possibly out-of-scope by the time the 'throw' is executed.

So (purely out of interest, as you are solving this another way...)

Could you try replacing :exit with an instance or class-based variable
like:

def initialize
@exit=:exit
end

And then refer to it in both your catch and throw ? (or at least your
catch..)

Again, based on what's been posted here - sounds like timing plays a
role here: maybe the 'puts' delays execution just-enough to keep the
thread-of-execution within the method for the 'throw' to find the
referring catch...?

This is quite an interesting problem...I'm learning quite a bit about
ruby just from watching the other posts ! :)

Cheers

John
 
J

Joel VanderWerf

John said:
Patrick,

Again total guesswork , but based on the other posts from people who
actually know what they are talking about... - sounds like the symbol
':exit' is possibly out-of-scope by the time the 'throw' is executed.

Symbols are literal values, so they are not affected by scope.
 
P

Patrick Li

I agree, it's a very ... interesting problem. (Frustrating at first, but
interesting afterwards).

It's a good guess, but setting @exit = :exit, didn't help.

I wish I could post a little sample code that exhibits the same
behavior, but I just can't seem to isolate it.

I'm playing fast and fancy with continuations, so that's probably
messing around with scopes quite a bit.
 

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
473,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top