Is this a bug or a feature?

Discussion in 'Ruby' started by Martin Jansson, Sep 6, 2007.

  1. irb(main):002:0> i=1
    => 1
    irb(main):003:0> until (i+=1)>5
    irb(main):004:1> p i
    irb(main):005:1> end
    2
    3
    4
    5
    => nil
    irb(main):006:0> RUBY_VERSION
    => "1.8.3"

    The condition is evaluated before the first iteration.

    At least it's consistent:

    irb(main):005:0> i = 1
    => 1
    irb(main):006:0> p i until (i+=1)>5
    2
    3
    4
    5
    => nil

    I think it makes "until" less useful. Why would anyone want this?
     
    Martin Jansson, Sep 6, 2007
    #1
    1. Advertisements

  2. What other behavior would you want, and why?
    Here are some specs for the current behavior of 'until'. They may help.
    http://rubyurl.com/12y
     
    Wilson Bilkovich, Sep 6, 2007
    #2
    1. Advertisements

  3. Martin Jansson

    kazaam Guest

    I think I means why the 1 is not printed like in other langues if you do this with repeat...until
     
    kazaam, Sep 6, 2007
    #3
  4. I would say this is a feature to answer you question.
    Just think of what gets printed when you do
    i = 1
    i = i + 1

    so you are saying
    until (i = i + 1) > 5
    p i
    end

    the second time the i is evaluated is in the until loop.


    ~Jeremy
     
    JeremyWoertink, Sep 6, 2007
    #4

  5. If you want a bottom tested loop then do it this way:

    irb(main):006:0> i=1
    => 1
    irb(main):007:0> begin
    irb(main):008:1* p i
    irb(main):009:1> end until (i+=1) > 5
    1
    2
    3
    4
    5
    => nil
    irb(main):010:0>

    Cheers-

    -- Ezra Zygmuntowicz
    -- Founder & Ruby Hacker
    --
    -- Engine Yard, Serious Rails Hosting
    -- (866) 518-YARD (9273)
     
    Ezra Zygmuntowicz, Sep 6, 2007
    #5
  6. Martin Jansson

    dblack Guest

    Hi --

    You can do:

    begin
    # do stuff
    end until condition


    David

    --
    * Books:
    RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242)
    RUBY FOR RAILS (http://www.manning.com/black)
    * Ruby/Rails training
    & consulting: Ruby Power and Light, LLC (http://www.rubypal.com)
     
    dblack, Sep 6, 2007
    #6
  7. def print_all(arr)
    until arr.empty?
    print ">", arr.shift, "<\n"
    end
    end

    Try this with post checked conditions and an empty array as argument.
    Language designers seem to think otherwise. You described the logic of
    loops with prechecked conditions which abound in programming languages -
    for decades already.

    Kind regards

    robert
     
    Robert Klemme, Sep 6, 2007
    #7
  8. Thats just confusing. Why does that work different then "do_stuff until
    condition".

    I'm used to do things like this:
    a= n
    until (a*= 3.0)<=450.0
    # do stuff
    end

    I think it is more readable. You get the start value, the incrementer
    and the stop condition nicely grouped together. You also get more
    effective code, if the penalty for evaluating the condition is high. I'm
    not a native english speaker, but I think it feels more in line with
    natural languages as well as "mathematical language". And it's a lot
    more like how you do things in real life.

    Using the loop method would mean that I had to introduce a new scope.
    Which, sometimes, means that I have to remember to "declare" a lot of
    variables outside that scope. Even those that are never used. A lot of
    unecessary code attract bugs like sugar. I like Ruby's block iterators,
    but many times it is wrong to use them.
     
    Martin Jansson, Sep 11, 2007
    #8
  9. Martin Jansson

    Phrogz Guest

    Consider this:
    if foo() then
    bar()
    end

    bar() if foo()

    In both cases foo() is called before bar(), even though in one of the
    cases it appears later in source code. The 'if' can go in different
    places. Similarly with while and until. Now, sometimes you (both the
    general populace and you in particular) want to evaluate after the
    first iteration. For such cases we need a different syntax.

    Do you have a better suggestion for how to differentiate between
    evaluate-first and evaluate-after-one-iteration, that is also
    consistent with if/unless?
     
    Phrogz, Sep 11, 2007
    #9
  10. In Pascal, "until" differs from "while" in two ways:

    1. "While" exits the loop when the condition is false;
    "until" exits when the condition is true.
    2. "While" checks the condition at the top of the loop;
    "until" checks at the bottom of the loop.

    In Ruby, "until" differs from "while" in only one way:

    1. "While" exits the loop when the condition is false;
    "until" exits when the condition is true.

    You could say that "until" is to "while" as "unless" is
    to "if".

    Ruby is more flexible than Pascal in that the both
    "while" and "until" can check the condition either at
    the top or the bottom of the loop.


    # Count to 5, checking at the top of the loop.
    i = 0
    while (i += 1) <= 5
    print i, " "
    end
    puts

    # Count to 5, checking at the top of the loop.
    i = 0
    until not (i += 1) <= 5
    print i, " "
    end
    puts

    # Count to 5, checking at the bottom of the loop.
    i = 1
    begin
    print i, " "
    end while (i += 1) <= 5
    puts

    # Count to 5, checking at the bottom of the loop.
    i = 1
    begin
    print i, " "
    end until not (i += 1) <= 5
    puts


    Now, what about this?

    p i until (i+=1) > 5

    That is merely perlish shorthand for

    until (i+=1) > 5
    p i
    end

    just as

    p i if i < 6

    is perlish shorthand for

    if i < 6
    p i
    end

    If that seems confusing, don't use it.
     
    William James, Sep 12, 2007
    #10
  11. Here is what I understand based on Pascal.

    <waits for the laughing to stop>

    There are two main kinds of this loop:

    repeat..until

    while..do

    In the repeat..until (our own version of the until) it does things then
    checks for the break condition. In the while loop, it checks then does
    things.

    In our example here, we have:

    i=1
    until (i+=1)>5
    p i
    end

    The question is, when does it evaluate? When I learned basic algebra, I
    was taught to figure out the things inside the parens first. I think
    that is what is done here. Therefore, the first thing done is to
    increment, then evaluate.

    To get what you seem to want, you would need to evaluate before you
    increment, which would look more like this:

    i = 1
    until i>5
    p i
    i+=1
    end

    You were telling it to increment, THEN evaluate. That being the case,
    it would not be a bug. IMHO
     
    Lloyd Linklater, Sep 12, 2007
    #11
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.