Return from a block?

  • Thread starter Howard Lewis Ship
  • Start date
H

Howard Lewis Ship

I've had a couple of places where I really needed to just return from
a block. From what I can see, if my block is inside a method, the
return will return from the method, not return control *to* the
method. I've ended up writing some very Pascal like code:

Find.find(*ARGV) do |f|

if f =~ /[CVS|SVN]/
Find.prune
else
$matches += 1 if match?(f)
end
end

Where what I'd prefer to write would be:

Find.find(*ARGV) do |f|

if f =~ /[CVS|SVN]/
Find.prune
return-from-block-to-method
end

$matches += 1 if match?(f)
end


Is there a way to return control from the block to the method?

--
Howard M. Lewis Ship
Independent J2EE / Open-Source Java Consultant
Creator, Jakarta Tapestry
Creator, Jakarta HiveMind

Professional Tapestry training, mentoring, support
and project work. http://howardlewisship.com
 
J

Jamis Buck

next

Good luck.

To elaborate a little more:

a = proc { |i| next i+1 }
p a.call(5)

Hope that helps. I can understand why 'return' behaves like it does,
but there are times I wish there was a more intuitive keyword for
returning a value from a block. 'next' just feels wrong to me. :(

- Jamis
 
H

Howard Lewis Ship

Thanks ... there it is, plain as day, on page 345 of PickAxe 2nd edition.


To elaborate a little more:

a = proc { |i| next i+1 }
p a.call(5)

Hope that helps. I can understand why 'return' behaves like it does,
but there are times I wish there was a more intuitive keyword for
returning a value from a block. 'next' just feels wrong to me. :(

- Jamis


--
Howard M. Lewis Ship
Independent J2EE / Open-Source Java Consultant
Creator, Jakarta Tapestry
Creator, Jakarta HiveMind

Professional Tapestry training, mentoring, support
and project work. http://howardlewisship.com
 
B

Bertram Scharpf

Hi,

Am Donnerstag, 06. Jan 2005, 08:59:06 +0900 schrieb Howard Lewis Ship:
Thanks ... there it is, plain as day, on page 345 of PickAxe 2nd edition.

Sorry, where are the page numbers in the online version?

Bertram
 
B

Bertram Scharpf

Am Donnerstag, 06. Jan 2005, 18:32:52 +0900 schrieb Dave Thomas:
If you're looking at it online, it's probably the first edition.

What a surprise.

Anyway, I would have liked to know, what 'next <exp>' means.
Never mind; in the meantime I found out.

Bertram
 
E

E S

Jamis said:
To elaborate a little more:

a = proc { |i| next i+1 }
p a.call(5)

Hope that helps. I can understand why 'return' behaves like it does,
but there are times I wish there was a more intuitive keyword for
returning a value from a block. 'next' just feels wrong to me. :(

For just returning control, throw...catch should work, for returning
a value, Kernel.callcc? But Mr. Buck's solution is certainly shorter.

E
 
G

Gennady Bystritksy

E said:
Jamis said:
[Howard Lewis Ship <[email protected]>, 2005-01-06 00.11 CET]

Is there a way to return control from the block to the method?


next

Good luck.



To elaborate a little more:

a = proc { |i| next i+1 }
p a.call(5)

Hope that helps. I can understand why 'return' behaves like it does,
but there are times I wish there was a more intuitive keyword for
returning a value from a block. 'next' just feels wrong to me. :(


For just returning control, throw...catch should work, for returning
a value, Kernel.callcc? But Mr. Buck's solution is certainly shorter.

throw...catch can be used for returning a value as well, by the way. A
second parameter to "throw" is used as a return value from "catch".

Gennady.
 
S

Sea&Gull

Bertram said:
Am Donnerstag, 06. Jan 2005, 18:32:52 +0900 schrieb Dave Thomas:



What a surprise.

Anyway, I would have liked to know, what 'next <exp>' means.
Never mind; in the meantime I found out.

This C code may illustrate how "next", "break", "redo" behave
in Ruby:

/*****************************/
while (condition) {
label_redo:

goto label_next; /* next */
goto label_break; /* break */
goto label_redo; /* redo */

/* some code */

label_next:

}

label_break:

/*****************************/
 
B

Bertram Scharpf

Hi,

Am Freitag, 07. Jan 2005, 01:41:30 +0900 schrieb Sea&Gull:
This C code may illustrate how "next", "break", "redo" behave
in Ruby:

while (condition) {
label_redo:

goto label_next; /* next */
goto label_break; /* break */
goto label_redo; /* redo */

/* some code */

label_next:

}

label_break:

The question was not where execution continues but what
happens with an expression given after `next'.

I think this behaviour has to do with an other aspect:

def f ; yield ; end
def g ; 5.times { |i| f { break }; print i, '-' } ; end
puts g

So, `break' etc. do not actually leave loops but just
communicate with the calling `yield' that does the jump, to
the end of the surrounging loop or function, whatever comes
next.

Please blame me if I'm wrong.

Bertram
 
S

Sam Stephenson

For just returning control, throw...catch should work, for returning
a value, Kernel.callcc? But Mr. Buck's solution is certainly shorter.

Another way to do it is to rescue LocalJumpError.

| def yield_with_return_value(*args)
| yield *args
| rescue LocalJumpError => e
| e.exit_value
| end
|
| def foo(&block)
| yield_with_return_value &block
| end

irb(main):001:0> foo {return "hello"; "this is not returned"}
=> "hello"
irb(main):002:0> foo {"bar"}
=> "bar"

Sam
 
S

Sam Stephenson

Another way to do it is to rescue LocalJumpError.

| def yield_with_return_value(*args)
| yield *args
| rescue LocalJumpError => e
| e.exit_value
| end
|
| def foo(&block)
| yield_with_return_value &block
| end

irb(main):001:0> foo {return "hello"; "this is not returned"}
=> "hello"
irb(main):002:0> foo {"bar"}
=> "bar"

Sorry, I should make it a bit clearer that the block's return value is caught:

| def foo(&block)
| value = yield_with_return_value &block
| "baz " + value
| end

irb(main):001:0> foo {return "hello"; "this is not returned"}
=> "baz hello"
irb(main):002:0> foo {"bar"}
=> "baz bar"

Sam
 
S

Sea&Gull

The question was not where execution continues

Sorry, I did not undestand you clearly :)
but what
happens with an expression given after `next'.

What do you mean asking "what happens"?
I think this behaviour has to do with an other aspect:

def f ; yield ; end
def g ; 5.times { |i| f { break }; print i, '-' } ; end
puts g

*Perhaps*, your task may be solved by a tad redesign of
control structures:

def f(i); yield i; end

def g
5.times { |i|
break if f(i){|i| i == 3}
print i, '-'
}
puts "\nEnd of g"
end

puts g
So, `break' etc. do not actually leave loops

They "leave" _current_ block.
In the example you gave above "break" leaves
the block "{ break }".
but just
communicate with the calling `yield'

afaik, "yield" neither here not there.
It does not influence on the behaviour
of "break".
 

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,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top