How `next` works in ruby with `unless`?

On Tue, Mar 5, 2013 at 12:53 PM, Robert K.
[email protected] wrote:

accept two (syntax error).
$ ruby -ce ‘f { next 1 }’
^

It’s getting weirder - especially since the value(s) passed to next
are not used for anything as far as I can see. And it wouldn’t make
sense, would it? I mean, next is different from break which can be
used to return a value from an iteration.

next val causes an exit from a block, returning val. In a block
passed to Kernel#loop, the value is discarded; so Kumar’s next puts 'hi' just causes ‘hi’ to be printed but the nil return value of puts
is discarded.

break val also exits from a block, returning val, but in some cases
also exits from the method calling the block. I wrote a test case for
this on my work computer, but I don’t have access to it here; but I
seem to recall that break in a lambda simply exits the block, while
break in a proc exits the method. (If you create the proc by passing a
block to Proc.new, and then pass that proc to another method, which
calls it, break will raise a LocalJumpError, since the original stack
frame of Proc.new no longer exists.)

they values you used for next are returned by yield …
(so all block functions that does something different depending on the
block result does be affected like: .map, .select, .find, .group_by and
others )

On Tue, Mar 5, 2013 at 8:14 PM, Eric C.
[email protected] wrote:

break val also exits from a block, returning val, but in some cases
also exits from the method calling the block.

I’d rephrase that to “usually it exits from the method which invoked
the block” (lines 23 and 24 below seem to me the most usual use case).

I wrote a test case for
this on my work computer, but I don’t have access to it here; but I
seem to recall that break in a lambda simply exits the block, while
break in a proc exits the method. (If you create the proc by passing a
block to Proc.new, and then pass that proc to another method, which
calls it, break will raise a LocalJumpError, since the original stack
frame of Proc.new no longer exists.)

Yes, you are right:

irb(main):013:0> def f
irb(main):014:1> p “enter”
irb(main):015:1> p yield 1
irb(main):016:1> p yield 2
irb(main):017:1> p yield 3
irb(main):018:1> ensure
irb(main):019:1* p “exit”
irb(main):020:1> end
=> nil
irb(main):021:0> f {|i| i * 10}
“enter”
10
20
30
“exit”
=> 30

“next”:

irb(main):022:0> f {|i| next i * 10 if i == 1; i}
“enter”
10
2
3
“exit”
=> 3

“break”:

irb(main):023:0> f {|i| break i * 10 if i == 1; i}
“enter”
“exit”
=> 10
irb(main):024:0> f {|i| break i * 10 if i == 2; i}
“enter”
1
“exit”
=> 20

“local” break:

irb(main):028:0> f = lambda {|i| break i * 10 if i == 2; p i}
=> #<Proc:0x8025260c@(irb):28 (lambda)>
irb(main):029:0> 5.times &f
0
1
3
4
=> 5
irb(main):030:0> f = lambda {|i| next i * 10 if i == 2; p i}
=> #<Proc:0x8022ed10@(irb):30 (lambda)>
irb(main):031:0> 5.times &f
0
1
3
4
=> 5

Proc:

irb(main):032:0> f = Proc.new {|i| next i * 10 if i == 2; p i}
=> #Proc:0x801dc588@:32(irb)
irb(main):033:0> 5.times &f
0
1
3
4
=> 5
irb(main):034:0> f = Proc.new {|i| break i * 10 if i == 2; p i}
=> #Proc:0x801b76d4@:34(irb)
irb(main):035:0> 5.times &f
0
1
LocalJumpError: break from proc-closure
from (irb):34:in block in irb_binding' from (irb):35:in times’
from (irb):35
from /usr/bin/irb:12:in `’

Kind regards

robert

On Tue, Mar 5, 2013 at 8:07 PM, Hans M. [email protected]
wrote:

they values you used for next are returned by yield …
(so all block functions that does something different depending on the
block result does be affected like: .map, .select, .find, .group_by and
others )

Like with:

irb(main):025:0> 10.times.map {|i| next if i == 2;i*10}
=> [0, 10, nil, 30, 40, 50, 60, 70, 80, 90]

“next” is for a block about the same as a “return” for a method: the
current call is terminated at this point with the provided arguments
given to the caller (the “yield”). And since “next” is a keyword it
does make sense to have it follow the same syntax rules for arguments
like “return” and “break”.

Hans, thank you for the heads up!

Kind regards

robert