Return from a block?

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

[Howard Lewis Ship <hlship@gmail.com>, 2005-01-06 00.11 CET]

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

next

Good luck.

I think you may be asking for the "continuation":

  ->callcc do |p|
  -> for i in 1..10
  -> p.call if 5 ==i # On to end of block.
  -> print i
  -> end
  ->end # To after here.
1234nil

Also, just to round out:

  ->def t
  -> p =nil ;s=[1,2,3,4]
  -> callcc {|p|}
  -> print m =s.shift ;print ','
  -> p.call unless 3 ==m # Backward to end of block.
  ->end ;t # Otherwise onward.
1,2,3,nil

I've had a couple of places where I really needed to return control from

a block to the method. 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

By returning control to "the method," I think you mean as below. A
continuation sometimes is useful as a break (as here) and sometimes as a
continue statement. A fuller example is perhaps appropriate, as it's a
strange idea for non-Lisp programmers:

def aMethod
  # Following is a Ruby standard library kernel method
  # that makes a continuation object that when called,
  # transfers the program's flow of control to just below
  # its block.
  callcc do |afterCallccBlock|
    Find.find(*ARGV) do |f|
      if f =~ /[CVS|SVN]/
        Find.prune
        # Return-from-block-to-method
        afterCallccBlock.call # On to end of callcc block.
      end
      $matches += 1 if match?(f)
    end
  end
  # End of callcc block.
  # Rest of the method.
end # aMethod.

···

Howard Lewis Ship <hlship@gmail.com> Jan 6, 2005 at 08:11 AM wrote:

I've had a couple of places where I really needed to return control from

a block to the method. 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

By returning control to "the method," I think you mean as below. A
continuation sometimes is useful as a break (as here) and sometimes as a
continue statement. A fuller example is perhaps appropriate, as it's a
strange idea for non-Lisp programmers:

def aMethod
  # Following is a Ruby standard library kernel method
  # that makes a continuation object that when called,
  # transfers the program's flow of control to just below
  # its block.
  callcc do |afterCallccBlock|
    Find.find(*ARGV) do |f|
      if f =~ /[CVS|SVN]/
        Find.prune
        # Return-from-block-to-method
        afterCallccBlock.call # On to end of callcc block.
      end
      $matches += 1 if match?(f)
    end
  end
  # End of callcc block.
  # Rest of the method.
end # aMethod.

···

Howard Lewis Ship <hlship@gmail.com> Jan 6, 2005 at 08:11 AM wrote:

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. :frowning:

- Jamis

···

On 08:17 Thu 06 Jan , Carlos wrote:

[Howard Lewis Ship <hlship@gmail.com>, 2005-01-06 00.11 CET]
> Is there a way to return control from the block to the method?

next

Good luck.

--
Jamis Buck
jamis_buck@byu.edu
http://www.jamisbuck.org/jamis
------------------------------
"I am Victor of Borge. You will be assimil-nine-ed."

"Carlos" <angus@quovadis.com.ar> schrieb im Newsbeitrag news:20050105231702.GA4600@quovadis.com.ar...

[Howard Lewis Ship <hlship@gmail.com>, 2005-01-06 00.11 CET]

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

next

"break "could work, too.

Kind regards

    robert

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

···

On Thu, 6 Jan 2005 08:35:14 +0900, Jamis Buck <jamis_buck@byu.edu> wrote:

On 08:17 Thu 06 Jan , Carlos wrote:
> [Howard Lewis Ship <hlship@gmail.com>, 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. :frowning:

- Jamis

--
Jamis Buck
jamis_buck@byu.edu
http://www.jamisbuck.org/jamis
------------------------------
"I am Victor of Borge. You will be assimil-nine-ed."

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

Jamis Buck wrote:

···

On 08:17 Thu 06 Jan , Carlos wrote:

[Howard Lewis Ship <hlship@gmail.com>, 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. :frowning:

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

E

Hi,

···

Am Donnerstag, 06. Jan 2005, 08:59:06 +0900 schrieb Howard Lewis Ship:

On Thu, 6 Jan 2005 08:35:14 +0900, Jamis Buck <jamis_buck@byu.edu> wrote:
>
> a = proc { |i| next i+1 }
> p a.call(5)
>
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

--
Bertram Scharpf
Stuttgart, Deutschland/Germany
http://www.bertram-scharpf.de

E S wrote:

Jamis Buck wrote:

[Howard Lewis Ship <hlship@gmail.com>, 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. :frowning:

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.

···

On 08:17 Thu 06 Jan , Carlos wrote:

E

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

···

On Fri, 7 Jan 2005 00:38:59 +0900, E S <eero.saynatkari@kolumbus.fi> wrote:

If you're looking at it online, it's probably the first edition.

Cheers

Dave

···

On Jan 6, 2005, at 3:17 AM, Bertram Scharpf wrote:

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

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

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

···

On Thu, 6 Jan 2005 14:08:03 -0600, Sam Stephenson <sstephenson@gmail.com> wrote:

What a surprise.

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

Bertram

···

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

On Jan 6, 2005, at 3:17 AM, Bertram Scharpf wrote:

>>Thanks ... there it is, plain as day, on page 345 of PickAxe 2nd
>>edition.
>
>Sorry, where are the page numbers in the online version?
>
If you're looking at it online, it's probably the first edition.

--
Bertram Scharpf
Stuttgart, Deutschland/Germany
http://www.bertram-scharpf.de

Bertram Scharpf wrote:

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

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

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.

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:

/*****************************/

···

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

On Jan 6, 2005, at 3:17 AM, Bertram Scharpf wrote:

--
   s&g

Hi,

Bertram Scharpf wrote:
>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:

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

···

Am Freitag, 07. Jan 2005, 01:41:30 +0900 schrieb Sea&Gull:

--
Bertram Scharpf
Stuttgart, Deutschland/Germany
http://www.bertram-scharpf.de

The question was not where execution continues

Sorry, I did not undestand you clearly :slight_smile:

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

···

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&g