Forum: Ruby Idiom wanted: do-while

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Adam S. (Guest)
on 2005-12-13 00:35
(Received via mailing list)
So I was working on the quiz solution, and
I had some code like this:

   b = simulate board,m
   while another_turn?(b,m)
      b = simulate b,m
   end


If I was doing this in C, I'd use a do-while loop instead, to avoid
repeating the line outside the loop:

  b = board;
  do {
    b = simulate(b.m);
  }
  while ( another_turnta(b,m));

What's the do-while idiom in ruby?
I ended up with this, but it needs an extra flag variable:

  b,taketurn  = board,true
  while taketurn
    b = simulate b,m
    taketurn =  another_turn?(b,m)
  end

Is there a ruby idiom for do-while?

-Adam
James G. (Guest)
on 2005-12-13 00:44
(Received via mailing list)
On Dec 12, 2005, at 4:34 PM, Adam S. wrote:

> repeating the line outside the loop:
>   b,taketurn  = board,true
>   while taketurn
>     b = simulate b,m
>     taketurn =  another_turn?(b,m)
>   end
>
> Is there a ruby idiom for do-while?

I favor:

loop do
   # ... some action ...
   break unless ...
end

Hope that helps.

James Edward G. II
Mauricio F. (Guest)
on 2005-12-13 00:53
(Received via mailing list)
On Tue, Dec 13, 2005 at 07:42:59AM +0900, James Edward G. II wrote:
> >Is there a ruby idiom for do-while?
>
> I favor:
>
> loop do
>   # ... some action ...
>   break unless ...
> end

[ruby-core:06745]
gabriele renzi (Guest)
on 2005-12-13 01:14
(Received via mailing list)
Adam S. ha scritto:
> repeating the line outside the loop:
>
>   b = board;
>   do {
>     b = simulate(b.m);
>   }
>   while ( another_turnta(b,m));
>
> What's the do-while idiom in ruby?

you could do

begin
  ...
end while somecondition

but I seem to recall it is somewhat "deprecated" and you should follow
James' suggestion
Andy D. (Guest)
on 2005-12-13 01:23
(Received via mailing list)
You can also do
irb(main):011:0> begin
irb(main):012:1* puts "Once"
irb(main):013:1> end while nil
Once
=> nil

Which is what I usually do.

 - Andy D.
unknown (Guest)
on 2005-12-13 01:38
(Received via mailing list)
On Tue, 13 Dec 2005, Adam S. wrote:

> repeating the line outside the loop:
>  b,taketurn  = board,true
>  while taketurn
>    b = simulate b,m
>    taketurn =  another_turn?(b,m)
>  end
>
> Is there a ruby idiom for do-while?

   harp:~ > cat a.rb
   i = 0

   (
     p i
     i += 1
   ) while i < 3


   harp:~ > ruby a.rb
   0
   1
   2

cheers.

-a
Brian M. (Guest)
on 2005-12-13 01:56
(Received via mailing list)
On 12/12/05, removed_email_address@domain.invalid 
<removed_email_address@domain.invalid> wrote:
>    0
>    1
>    2

Not quite. That is just a while loop:

( puts "foo" ) while nil
.. nil

which is as always, equivalent to:

while nil
  puts "foo"
end


If you really need a do while loop it is not hard to use loop to
accomplish what you need. If you want something more complex you could
easily get this to work:

lambda do
 ...
end.while { ... }

All you would need is something like this:

class Proc
  def while
    loop do
      result = call
      return result unless yield
    end
  end
end

I am sure there is plenty of room for improving this example too.

Brian.
Adam S. (Guest)
on 2005-12-13 02:20
(Received via mailing list)
I was certain I had tried that....
But that works exactly the way I want.
Thanks,
-Adam
James G. (Guest)
on 2005-12-13 02:38
(Received via mailing list)
On Dec 12, 2005, at 6:19 PM, Adam S. wrote:

> I was certain I had tried that....
> But that works exactly the way I want.

But hopefully you followed the Ruby Core link in this thread and saw
Matz explaining how he would like to remove it from the language so
we shouldn't be using it.  Stick with loop do ... end.

James Edward G. II
Steve L. (Guest)
on 2005-12-13 03:38
(Received via mailing list)
On Monday 12 December 2005 05:42 pm, James Edward G. II wrote:

> > Is there a ruby idiom for do-while?
>
> I favor:
>
> loop do
>    # ... some action ...
>    break unless ...
> end

I do this quite a bit, but it's not structured programming and is a
little
like a goto. Break can improve readability on small loops, but on large
loops
maintained by multiple people it can become a nightmare.

SteveT

Steve L.
http://www.troubleshooters.com
removed_email_address@domain.invalid
James G. (Guest)
on 2005-12-13 03:50
(Received via mailing list)
On Dec 12, 2005, at 7:36 PM, Steve L. wrote:

>
> I do this quite a bit, but it's not structured programming and is a
> little
> like a goto. Break can improve readability on small loops, but on
> large loops
> maintained by multiple people it can become a nightmare.

Which is probably a sign that method calls are needed.  Heck, I think
two programmers working on the same loop is a sign of that.  ;)

James Edward G. II
Mark E. (Guest)
on 2005-12-13 04:05
(Received via mailing list)
I did, and I was curious about the statement

> Because it's hard for users to tell
>
>   begin <code> end while <cond>
>
> works differently from
>
>   <code> while <cond>
>
>
in what ways are they different?  Any code examples to show the
difference?
Andy D. (Guest)
on 2005-12-13 04:11
(Received via mailing list)
The begin end one functions like a do while loop, the body will always
get executed at least once,  wherease the <code> while <cond> will
only get exectuted if the cond is true.

irb(main):001:0> begin
irb(main):002:1* p "once"
irb(main):003:1> end while nil
"once"
=> nil
irb(main):004:0> p "once" while nil
=> nil

 - Andy D.
Stephen W. (Guest)
on 2005-12-13 09:24
(Received via mailing list)
Mark E. wrote:
>
>> Because it's hard for users to tell
>>
>>   begin <code> end while <cond>
>>
>> works differently from
>>
>>   <code> while <cond>
>>
> in what ways are they different?  Any code examples to show the difference?

Andy already answered, but I thought I'd take my shot at it too.

     begin <code> end while <cond>

is guaranteed to execute <code> at least one time; whereas,

     <code> while <cond>

may never execute <code> because it is exactly equivalent to

     while <cond> <code>

in the same way that

     if <cond> <code>

is equivalent to

     <code> if <cond>

The whole begin/end thing is definitely unnecessary, and can (and
frequently does) become a source of confusion; it's a good thing that
it's going away.  The sooner the better.

--Steve
Jacob F. (Guest)
on 2005-12-13 18:11
(Received via mailing list)
On 12/12/05, Steve L. <removed_email_address@domain.invalid> wrote:
> On Monday 12 December 2005 05:42 pm, James Edward G. II wrote:
> > loop do
> >    # ... some action ...
> >    break unless ...
> > end
>
> I do this quite a bit, but it's not structured programming and is a little
> like a goto.

I see no similarity. 'goto' is unstructured because the target point
is completely arbitrary; place a label in your code then jump right to
it. 'break' is completely structured; it's part of the structure of
the enclosing loop and its target is defined by that structure.

> Break can improve readability on small loops, but on large loops
> maintained by multiple people it can become a nightmare.

I agree with James; if the loop is long enough or complex enough for
these to be a problem, the body of the loop probably needs some
serious refactoring.

Jacob F.
Steve L. (Guest)
on 2005-12-14 03:22
(Received via mailing list)
On Tuesday 13 December 2005 11:09 am, Jacob F. wrote:
> I see no similarity. 'goto' is unstructured because the target point
> is completely arbitrary; place a label in your code then jump right to
> it. 'break' is completely structured; it's part of the structure of
> the enclosing loop and its target is defined by that structure.

Ahh -- I found a reference. See
http://en.wikipedia.org/wiki/Structured_programming, and note Dijkstra's
structured programming definition -- every block of code has one entry
point
and one exit point. Break statements clearly violate the "one exit
point"
rule. I was taught the Dijkstra definition at Santa Monica College.

That same page also lists a definition not demanding a single exit
point,
allowing for break. I saw a lot of that when I left Santa Monica College
and
programmed in the real world. I also saw code that was horribly
obfuscated by
break statements. More on that...

>
> > Break can improve readability on small loops, but on large loops
> > maintained by multiple people it can become a nightmare.
>
> I agree with James; if the loop is long enough or complex enough for
> these to be a problem, the body of the loop probably needs some
> serious refactoring.

It absolutely does. Trouble is, in many shops loops start out 8 lines of
code,
and over many, many years, maintenance programmers, many not
experienced,
most not being privy to original design considerations, add features
demanded
by management on ultra-tight schedules. A few years later it's 100 lines
of
code and the break statement is in the middle of it.

Under those circumstances, the once understandable break statement
authored by
the original programmer can result in unfathomable code, especially if
others
add more break statements.

What I'm saying isn't as important today as it was 15 years ago, when
many
programs were not object oriented. Obviously, something like
My_data.to_s can
easily be refactored just from its name. 15 years ago,
process_all_valid_incoming_paid_records() could not be.

By habit, I always think twice before using break or continue (redo in
Ruby).
If I still want to use it, then I go ahead.

SteveT

Steve L.
http://www.troubleshooters.com
removed_email_address@domain.invalid
James G. (Guest)
on 2005-12-14 03:37
(Received via mailing list)
On Dec 13, 2005, at 7:20 PM, Steve L. wrote:

>>
> entry point
> and one exit point.

The loop do ... end construct is infinite.  You must add a break to
end it.  With one break, it has exactly one entry and exit point.

> experienced,
> most not being privy to original design considerations, add
> features demanded
> by management on ultra-tight schedules. A few years later it's 100
> lines of
> code and the break statement is in the middle of it.

You may be describing where you work, but you are certainly not
describing where I do.  ;)

I've got two words for you:  Unit tests.  They were invented to
address every single issue you just listed (plus some!) and I assure
you, they work.  You really, really should give them a try.  It will
be the best gift you ever give yourself, I promise.

James Edward G. II
Jamis B. (Guest)
on 2005-12-14 03:52
(Received via mailing list)
Ok, I admit I'm coming onto this thread a bit late in the game, so
someone else might have already suggested this:

   i = 0
   begin
     puts i
     i += 1
   end until i > 10

- Jamis
Chad P. (Guest)
on 2005-12-14 10:40
(Received via mailing list)
On Wed, Dec 14, 2005 at 10:36:50AM +0900, James Edward G. II wrote:
>
> I've got two words for you:  Unit tests.  They were invented to
> address every single issue you just listed (plus some!) and I assure
> you, they work.  You really, really should give them a try.  It will
> be the best gift you ever give yourself, I promise.

It's certainly good policy to use unit tests.  On the other hand, coding
in a manner that is in any way less easy to maintain because you know
that the way you write code will ensure that the problem is taken care
of doesn't address the issue of what happens if someone else, with less
ingrained good habits, comes along and takes over.

Um.  I'm not entirely certain that was coherent.

--
Chad P. [ CCD CopyWrite | http://ccd.apotheon.org ]

unix virus: If you're using a unixlike OS, please forward
this to 20 others and erase your system partition.
James G. (Guest)
on 2005-12-14 15:48
(Received via mailing list)
On Dec 14, 2005, at 2:38 AM, Chad P. wrote:

> On the other hand, coding
> in a manner that is in any way less easy to maintain because you know
> that the way you write code will ensure that the problem is taken care
> of doesn't address the issue of what happens if someone else, with
> less
> ingrained good habits, comes along and takes over.

At the risk of sounding like a broken record, I think one of the big
advantages of Unit Tests is that they encourage you to code in a
manner that is easier to maintain (because it's also easier to test).

As for when someone else jumps in, you show them your test suit and
how it works and pray it's catching.  ;)  Seriously, you have to
worry about you first.  The rest of the world takes time.  (I did ask
in my last job interview if the company covered their software with
Unit Tests though!  :D  )

James Edward G. II
Jacob F. (Guest)
on 2005-12-14 18:24
(Received via mailing list)
On 12/13/05, Steve L. <removed_email_address@domain.invalid> wrote:
> >
> > I see no similarity. 'goto' is unstructured because the target point
> > is completely arbitrary; place a label in your code then jump right to
> > it. 'break' is completely structured; it's part of the structure of
> > the enclosing loop and its target is defined by that structure.
>
> Ahh -- I found a reference. See
> http://en.wikipedia.org/wiki/Structured_programming, and note Dijkstra's
> structured programming definition -- every block of code has one entry point
> and one exit point. Break statements clearly violate the "one exit point"
> rule. I was taught the Dijkstra definition at Santa Monica College.

I'll concede that, but refer to James comment (about one break in a
loop do...end being a single exit point). However, I'd lean towards
the looser definition you mention below. Otherwise, having a function
with more than one return in it (e.g. "return false unless
precondition") would not be structured, and I'd much rather be able to
return early then have to wrap the remainder of the function body in
an if statement.

> That same page also lists a definition not demanding a single exit point,
> allowing for break. I saw a lot of that when I left Santa Monica College and
> programmed in the real world. I also saw code that was horribly obfuscated by
> break statements. More on that...

Just because break can be abused doesn't make it wrong.

> by management on ultra-tight schedules. A few years later it's 100 lines of
> code and the break statement is in the middle of it.

Hence the need for continuous refactoring. If that's not taking place,
it management's and/or the developers' fault, not the break
statement's.

> Under those circumstances, the once understandable break statement authored by
> the original programmer can result in unfathomable code, especially if others
> add more break statements.

Again, abuse doesn't mean the item being abused is at fault.

> What I'm saying isn't as important today as it was 15 years ago, when many
> programs were not object oriented. Obviously, something like My_data.to_s can
> easily be refactored just from its name. 15 years ago,
> process_all_valid_incoming_paid_records() could not be.

Point conceded.

> By habit, I always think twice before using break or continue (redo in Ruby).
> If I still want to use it, then I go ahead.

That's a good principle, one I wish many programmers would follow. I,
too, have been bitten by unclear breaks. But I've also been bitten by
unclear conditions in 'if' statements, 'while' statements when 'each'
with a block should have been used, etc. That doesn't mean that 'if'
statements or 'while' statements should be considered harmful. This is
the impression I got about your opinion regarding 'break' when you
lumped it with 'goto'.

Jacob F.
Steve L. (Guest)
on 2005-12-14 20:19
(Received via mailing list)
On Wednesday 14 December 2005 11:24 am, Jacob F. wrote:

> Hence the need for continuous refactoring. If that's not taking
> place, it management's and/or the developers' fault, not the
> break statement's.

It's definitely not the break statement's fault. It might not be the
developer's or management's either. It might be the fault of the
marketplace, which in turn is nobody's fault -- it is what it is.

If taking the time to understand the code, in preparation for
refactoring, will cause a loss of customers, refactoring can wait
(and unfortunately usually waits until a clean rewrite).

That being said, I've always tried to refactor when possible. A lot
of times management doesn't even know -- you just rewrite
problematic parts.

By the way, how do you like often maintained, never refactored code
where they have three different variables representing essentially
the same thing, and you need to decide which one to use and which
one to set?

SteveT

Steve L.
http://www.troubleshooters.com
removed_email_address@domain.invalid
Jacob F. (Guest)
on 2005-12-14 20:28
(Received via mailing list)
On 12/14/05, Steve L. <removed_email_address@domain.invalid> wrote:
> If taking the time to understand the code, in preparation for
> refactoring, will cause a loss of customers, refactoring can wait
> (and unfortunately usually waits until a clean rewrite).

That's unfortunate if you feel that you're in that position (and I can
sympathize, I've been there).

In my mind, refactoring is *part* of code maintenance. When you need
to fix a bug or add functionality, watch for opportunities to
refactor. Refactoring is part of writing the new code, not something
that's applied after the new code is added.

If you're understanding of the code insufficient to make necessary
refactorings while making the change, your understanding of the code
is insufficient to be making the change in the first place.

> That being said, I've always tried to refactor when possible. A lot
> of times management doesn't even know -- you just rewrite
> problematic parts.

Exactly.

> By the way, how do you like often maintained, never refactored code
> where they have three different variables representing essentially
> the same thing, and you need to decide which one to use and which
> one to set?

I assume that's a rhetorical question... :)

Jacob F.

P.S. Thanks for the discussion; I don't mean to be attacking you or
your practices, just evangelizing. :)
This topic is locked and can not be replied to.