Forum: Ruby How `next` works in ruby with `unless` ?

Posted by Kumar R. (kumar_r)
on 2013-03-04 22:58
The `next` statement is used to skip a part of the loop and continue
with the next iteration of the loop. It can be used in combination with
`for` and `while` statements.

I have seen people using next if there is complicated piece of code
after some condition is being evaluated i.e

    next if @state!=:some_state
    # some long complicated code

Now here I have played with the `next` in my `IRB` as below :

    n = 1
    loop do
    n = n + 1
    next unless n == 10
    print "Good"
    break
    end
    # Good=> nil

The above one understood. Nicely clear.

    n = 1
    #=> 1
    loop do
    print "#{n}"
    n = n + 1
    next puts "hi" unless n == 5
    p "good"
    break
    end
    #1hi
    #2hi
    #3hi
    #4"good"
    #=> nil

In the above code, couldn't understand about which order the lines `puts
"hi"` and `unless n == 5` executed. Which executed first?

The below one leads to the `infinite Loop`.

    n = 1
    #=> 1
    loop do
    print "#{n}"
    n = n + 1
    next puts "hi"; 2 + 3 unless n == 5
    p "good"
    break
    end

whereas this one is good:

    n = 1
    #=> 1
    loop do
    print "#{n}"
    n = n + 1
    next puts "hi", 2 + 3 unless n == 5
    p "good"
    break
    end

    #1hi
    #5
    #2hi
    #5
    #3hi
    #5
    #4"good"
    #=> nil

Please help me here to understand - how does this one resolve that
`forever` loop ?
Posted by Joel Pearson (virtuoso)
on 2013-03-04 23:07
Learn what semicolons do in Ruby.
Posted by Matthew Kerwin (mattyk)
on 2013-03-04 23:18
(Received via mailing list)
What Joel said.

Also, why are you calling 'next nil' ?
Posted by Kumar R. (kumar_r)
on 2013-03-04 23:20
Matthew Kerwin wrote in post #1100097:
> What Joel said.
>
> Also, why are you calling 'next nil' ?

My interest is only with that part :

 n = 1
    #=> 1
    loop do
    print "#{n}"
    n = n + 1
    next puts "hi" unless n == 5
    p "good"
    break
    end
    #1hi
    #2hi
    #3hi
    #4"good"
    #=> nil

In the above code, couldn't understand about which order the lines `puts
"hi"` and `unless n == 5` executed. Which executed first?

the rest one I pasted here by mistake. Sorry for that. Please ignore the 
second part.
Posted by Cliff Rosson (beaon)
on 2013-03-04 23:27
(Received via mailing list)
People are so incredibly brash on this forum sometimes. Makes for a cold
community.  :)
Posted by Matthew Kerwin (mattyk)
on 2013-03-04 23:39
(Received via mailing list)
On 5 March 2013 08:26, Cliff Rosson <cliff.rosson@gmail.com> wrote:

> People are so incredibly brash on this forum sometimes. Makes for a cold
> community.  :)
>

Only to certain users.  I know it reflects on us poorly, but we've been
over things like "the return value of puts" before with this (or an
identical?) user.

The line:
    next puts "hi"
is already weird, without then conditionally executing it with `unless n 
==
5`

The question should be: how did you get your code into this state in the
first place?  Rather than trying to understand how the interpreter 
handles
it.
Posted by John W Higgins (Guest)
on 2013-03-04 23:52
(Received via mailing list)
What do you think the only possible order of execution would be? It's 
not
difficult to look at that and figure out exactly which section is 
executed
first

Also - if you are going to test something - at least print out the 
variable
in question AFTER you increment it - it makes your "debugging output" 
look
rather much less helpful to you.

Maybe if you got this it would make more sense to you

2hi
3hi
4hi
5"good"

??

http://www.ruby-doc.org/docs/ProgrammingRuby/html/... -
look at the "if and unless modifiers" section.

There is also the notion that there is ZERO reason for you to need to 
write
something more complex then necessary when learning something.

This works just as fine and you would understand it.

n = 1
loop do
  n = n + 1
  print "#{n}"
  if n < 5
    puts 'hi'
    next
  end
  p 'good'
  break
end

You are continually trying to add 20 different unknown concepts into 
your
thought stream - take things one at a time - learn them well - then 
start
mixing and matching concepts to see how it comes together.

John

BTW - even if the parser takes the next puts 'hi' unless n == 5 concept 
-
that's really just not code that is used by anyone that I've seen. 
Again,
mixing too many concepts for no gain at all.
Posted by Kumar R. (kumar_r)
on 2013-03-05 00:00
John W Higgins wrote in post #1100104:
> What do you think the only possible order of execution would be? It's
> not

I did that after reading the description - `The `next` statement is used
to skip a part of the loop and continue with the next iteration of the
loop.`

This is too straight statement and I understood. I just tried the above
to see what was not mentioned in that description - which is - How
`next` reacts when it would get anything between it and `while` or `if`
or `unless` condition. Just to see that behavior and for which I wrote 
the
line : "next puts "hi" unless n == 5 " .



> mixing too many concepts for no gain at all.
Posted by Garthy D (Guest)
on 2013-03-05 03:58
(Received via mailing list)
Hi Cliff,

Unfortunately, for the last little bit, the list has been under siege by
a single person posting with multiple pseudonyms, posting a barrage of
ill-formed questions in strained, tortured English, disrespecting the
time and effort of the people who take the time to respond by outright
ignoring the answers, and asking each person responding personally for
more and more information, whilst refusing to make any effort to apply
the information gained; until the poor person, who was only trying to
help in the first place, finally gives up out of frustration. Attempts
to either reason with, prevent, or call out this person on their
behaviour, are met with type of righteous indignation that can only be
mustered by someone with a complete and utter disregard for anyone and
anything but themselves and their own personal convenience- or someone
simply enjoying the frustration that they are causing by acting in this
way. Sometimes it can be hard to tell the difference.

People are dealing with this noise in their own way, and there is some
disagreement about how to handle it. Some people are, understandably, a
bit on edge at the moment. The list, sadly, will be worse for it.

Eventually things will settle down again, and the community will again
appear to be as it has (always?) been- a collection of genuinely
considerate and helpful people messing about with the intricacies of an
interesting and useful language. :)

Cheers,
Garth
Posted by Cliff Rosson (beaon)
on 2013-03-05 04:50
(Received via mailing list)
Yes. I, as a lurker, I have more or less picked up on the fact that
something was going on. Seeing some of these threads out of context is
sometimes hard to place. Hopefully things will improve in the future!


On Mon, Mar 4, 2013 at 6:56 PM, Garthy D <
Posted by unknown (Guest)
on 2013-03-05 07:14
(Received via mailing list)
Am 04.03.2013 23:26, schrieb Cliff Rosson:
> People are so incredibly brash on this forum sometimes. Makes for a cold
> community.  :)

I always perceived the list members as *extremely* friendly,
patient, helpful, and willing to share their profound knowledge.

A big "Thank you" to all for that :)



Only at the moment I think the patience of many list members is
stretched to its limits, because some user keeps posting (under
various aliases) pointless, randomly cobbled together code
that he cannot understand because he keeps ignoring our advice
and refuses to gain a basic understanding of the language.

It's sad that this reflects badly on the list itself...
Posted by Robert Klemme (robert_k78)
on 2013-03-05 15:25
(Received via mailing list)
On Tue, Mar 5, 2013 at 7:13 AM,  <sto.mar@web.de> wrote:

> I always perceived the list members as *extremely* friendly,
> patient, helpful, and willing to share their profound knowledge.
>
> A big "Thank you" to all for that :)

You're welcome!

> Only at the moment I think the patience of many list members is
> stretched to its limits, because some user keeps posting (under
> various aliases) pointless, randomly cobbled together code
> that he cannot understand because he keeps ignoring our advice
> and refuses to gain a basic understanding of the language.

Is it really proven that there is actually a single person behind 
various nicks?

> It's sad that this reflects badly on the list itself...

We're all human.  I believe some people did not yet fully realize that
you cannot *force* someone to learn or change in the ways one thinks
is best for them.  If one realizes that one's advice is not heard then
it's usually best to just move on.

Cheers

robert
Posted by Peter Hickman (Guest)
on 2013-03-05 16:08
(Received via mailing list)
On 5 March 2013 14:25, Robert Klemme <shortcutter@googlemail.com> wrote:

> Is it really proven that there is actually a single person behind various
> nicks?
>
>
I'm not entirely sure about this. Love U Ruby had
some idiosyncratic phrases that none of the others seem to have used, 
"bad
mentalities" was one. He was fond of the word "mentalities". I do not 
think
any of the other have used it. But this does not mean that the rest are 
not
themselves sockpuppets of another party.

Having said that things seem to happen in clusters so I am willing to
believe that we have suddenly had a bunch of oxygen thieves on our 
hands.
This is the nature of the eternal september :(
Posted by Joel Pearson (virtuoso)
on 2013-03-05 16:50
They all use backticks instead of quotes. They all write with the same 
cadence. They all use similar or identical terminology. They are all 
accounts created recently and in sequence, corresponding to complaints 
about the previous ID's activity. Looks pretty likely to be the same 
vampire to me.
Posted by Kumar R. (kumar_r)
on 2013-03-05 19:18
Kumar R. wrote in post #1100105:
> John W Higgins wrote in post #1100104:
>> What do you think the only possible order of execution would be? It's
>> not
>
> I did that after reading the description - `The `next` statement is used
> to skip a part of the loop and continue with the next iteration of the
> loop.`

> line : "next puts "hi" unless n == 5 " .

next generally used to skip the part of execution and send the control 
to the beginning. But how the in between part puts "hi" has been 
executed. Why does next not skip this statement ?
Posted by unknown (Guest)
on 2013-03-05 19:23
(Received via mailing list)
Am 05.03.2013 19:18, schrieb Kumar R.:
> Kumar R. wrote in post #1100105:

>> line : "next puts "hi" unless n == 5 " .
>
> next generally used to skip the part of execution and send the control
> to the beginning. But how the in between part puts "hi" has been
> executed. Why does next not skip this statement ?

Nobody writes code like this, so why care.
Posted by Hans Mackowiak (hanmac)
on 2013-03-05 19:33
Kumar R. wrote in post #1100229:
> Kumar R. wrote in post #1100105:
>> John W Higgins wrote in post #1100104:
>>> What do you think the only possible order of execution would be? It's
>>> not
>>
>> I did that after reading the description - `The `next` statement is used
>> to skip a part of the loop and continue with the next iteration of the
>> loop.`
>
>> line : "next puts "hi" unless n == 5 " .
>
> next generally used to skip the part of execution and send the control
> to the beginning. But how the in between part puts "hi" has been
> executed. Why does next not skip this statement ?



its because puts "hi" is evaluated first and THEN the result of it is 
given to the next keyword (in the case of puts it is nil)
Posted by Robert Klemme (robert_k78)
on 2013-03-05 19:33
(Received via mailing list)
On Tue, Mar 5, 2013 at 7:23 PM,  <sto.mar@web.de> wrote:
>> executed. Why does next not skip this statement ?
Probably because arguments are always evaluated before the "method"
they are handed over to.

> Nobody writes code like this, so why care.

I wasn't even aware that next accepts an argument - funnily it won't
accept two (syntax error).

Cheers

robert
Posted by Hans Mackowiak (hanmac)
on 2013-03-05 19:38
Robert Klemme wrote in post #1100233:
> On Tue, Mar 5, 2013 at 7:23 PM,  <sto.mar@web.de> wrote:
>>> executed. Why does next not skip this statement ?
> Probably because arguments are always evaluated before the "method"
> they are handed over to.
>
>> Nobody writes code like this, so why care.
>
> I wasn't even aware that next accepts an argument - funnily it won't
> accept two (syntax error).
>
> Cheers
>
> robert

hm it does:

[1,2,3,4].map {|d| next d,4,5;p "is not printed" }
#=> [[1, 4, 5], [2, 4, 5], [3, 4, 5], [4, 4, 5]]
Posted by Robert Klemme (robert_k78)
on 2013-03-05 19:54
(Received via mailing list)
On Tue, Mar 5, 2013 at 7:38 PM, Hans Mackowiak <lists@ruby-forum.com> 
wrote:
> Robert Klemme wrote in post #1100233:
>> On Tue, Mar 5, 2013 at 7:23 PM,  <sto.mar@web.de> wrote:
>>>> executed. Why does next not skip this statement ?
>> Probably because arguments are always evaluated before the "method"
>> they are handed over to.
>>
>>> Nobody writes code like this, so why care.
>>
>> I wasn't even aware that next accepts an argument - funnily it won't
>> accept two (syntax error).

> hm it does:
>
> [1,2,3,4].map {|d| next d,4,5;p "is not printed" }
> #=> [[1, 4, 5], [2, 4, 5], [3, 4, 5], [4, 4, 5]]

Oh, I tested only with brackets.  Here's the whole story

$ ruby -ce 'f { next }'
Syntax OK
$ ruby -ce 'f { next 1 }'
Syntax OK
$ ruby -ce 'f { next 1, 2 }'
Syntax OK
$ ruby -ce 'f { next 1, 2, 3 }'
Syntax OK
$ ruby -ce 'f { next(1) }'
Syntax OK
$ ruby -ce 'f { next(1, 2) }'
-e:1: syntax error, unexpected ',', expecting ')'
f { next(1, 2) }
           ^

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.

Cheers

robert
Posted by Hans Mackowiak (hanmac)
on 2013-03-05 20:07
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 )
Posted by Eric Christopherson (echristopherson)
on 2013-03-05 20:14
(Received via mailing list)
On Tue, Mar 5, 2013 at 12:53 PM, Robert Klemme
<shortcutter@googlemail.com> 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.)
Posted by Robert Klemme (robert_k78)
on 2013-03-05 22:25
(Received via mailing list)
On Tue, Mar 5, 2013 at 8:07 PM, Hans Mackowiak <lists@ruby-forum.com> 
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
Posted by Robert Klemme (robert_k78)
on 2013-03-05 22:26
(Received via mailing list)
On Tue, Mar 5, 2013 at 8:14 PM, Eric Christopherson
<echristopherson@gmail.com> 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@(irb):32>
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@(irb):34>
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 `<main>'

Kind regards

robert
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.