20

Have I missed something or is there no built-in which mimics the behaviour of do ... while loop?

I am looking for a construct that evaluates procedure once and then repeatedly evaluates it while test is not fulfilled.

I'm ended up using:

While[procedure; test, {}]

But clearly the second argument is redundant, so I have a feeling that I'm missing something. Maybe not, but I just want to be sure :)

Kuba
  • 136,707
  • 13
  • 279
  • 740
  • 2
    While[(procedure;test)] - parens. optional, makes it clear I think... – ciao Mar 18 '14 at 10:06
  • 3
    Not sure how a compound statement is abuse...first example under scope in the docs does it in compact form. – ciao Mar 18 '14 at 10:12
  • @rasher Agree, abuse is not a good word. I mean, docs say first arg is a test which may be missleading and the example you are referring to is ok but formed in easy-to-overlook way. Especially for new users. I think it could be an useful topic for future visitors. – Kuba Mar 18 '14 at 10:17
  • LOL - I was puzzled why "@" was not working, just noticed you were the OP. I think you're just messing with us ;-}. – ciao Mar 18 '14 at 10:19
  • @rasher :D no I'm not. When I was starting to learn MMA I was digging through docs quite alot (wasn't aware of M.SE). But documentation has not lead me to the answer, because of the issues I've mentioned above. I figured it out but had a feeling that it is not the way it should be done in MMA. – Kuba Mar 18 '14 at 10:24
  • 1
    @rasher To the conclusion: I don't think there should be a separate function. My goal is to show to future beginners :), who may have doubts similar to mine in the past, that this is the way. – Kuba Mar 18 '14 at 10:29
  • Sorry Kuba, but I'm trying to be even-handed here and this is pretty directly found in the documentation. Closed. :-/ – Mr.Wizard Mar 19 '14 at 09:56
  • @Mr.Wizard Don't be sorry :P I can agree because it is common thing that I'm missreading things that are obvious for others. This topic was meant to be for such people like me, in terms of docs interpretation, if there are any :p – Kuba Mar 19 '14 at 09:59
  • @Mr.Wizard Ha! maybe it is simple mistake but it is my mostly viewed question :P I'm not the only one :) unless it's because of someone posted it on 9gag or sth for fun ;P – Kuba Sep 30 '14 at 07:12
  • Kuba, that's interesting. I suppose it may be a popular search. You just got my +1 for that. :-) Still I think I'll leave this closed unless someone comments that they have something special to post. – Mr.Wizard Sep 30 '14 at 14:27
  • 1
    DoWhile exists as a function and as a macro rule in GeneralUtilities`. – Karsten7 Oct 05 '16 at 06:41

4 Answers4

18

While While[procedure; test] works, it looks very similar to While[test, procedure]. The only difference is ; vs ,. While is not the most commonly used construct, so when used like this there's a high chance of misunderstanding/misreading.

If readability/reliability is a concern (for example a collaboratively developed published package), I'd use the longer but clearer

While[True,
  procedure;
  If[Not[test], Break[]]
]

The only argument here is readability and "defensive programming" (extra effort to avoid accidental problems). Readability is subjective. If you are the only person who writes/reads the code and you get used to this use of While (and thus always pay special attention to the , vs ;) then this argument doesn't apply.

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
13

Version 13.1 introduced the function Until

Until[test,body] evaluates body and then test, repetitively, until test first gives True.

Jason B.
  • 68,381
  • 3
  • 139
  • 286
7

Why not write your own and place it in your init.m file?

SetAttributes[DoWhile, HoldAll];

DoWhile[procedure_, test_] := While[procedure; test]
Greg Hurst
  • 35,921
  • 1
  • 90
  • 136
4

Here's another way to write your own:

SetAttributes[doWhile, HoldAll];    
doWhile[expr_, test_] := CompoundExpression[expr, While[test, expr]]

Or just:

doWhile[expr_, test_] := (expr; While[test, expr])
RunnyKine
  • 33,088
  • 3
  • 109
  • 176