1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

WAD Incorrect _do_loop values

Discussion in 'Support' started by Steve Fabian, Sep 22, 2013.

  1. Steve Fabian

    Joined:
    May 20, 2008
    Messages:
    3,523
    Likes Received:
    4
    The value of _do_loop at the termination of the DO loop is often one more than the numer of times the loop was actually executed.

    Program:
    Code:
    @echo off
    do while 0 gt 1
      echo in while loop: %_do_loop
    enddo
    echo after while %_do_loop
    
    set x=0
    do forever
      set /a/q x+=1
      echo in forever loop x=%x dl=%_do_loop
      if %x GT 2 leave
    enddo
    echo after forever loop %_do_loop
    
    do n = 1 to 3
      echo in counted loop n=%n dl=%_do_loop
    enddo
    echo after counted loop n=%n dl=%_do_loop
    
    Report:
    Code:
    after while 1
    in forever loop x=1 dl=1
    in forever loop x=2 dl=2
    in forever loop x=3 dl=3
    after forever loop 3
    in counted loop n=1 dl=1
    in counted loop n=2 dl=2
    in counted loop n=3 dl=3
    after counted loop n=4 dl=4
    
    Only the forever loop reports _do_loop correctly.
     
  2. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,885
    Likes Received:
    29
    In my opinion, they all get it right. Think of it this way: _DO_LOOP starts at 0 and whenever the DO condition is tested, it is incremented.
     
  3. rconn

    rconn Administrator
    Staff Member

    Joined:
    May 14, 2008
    Messages:
    9,808
    Likes Received:
    82
    WAD. Like every other programming language in the world, the counter is incremented, then checked against the limit value. If it is greater, it falls out of the loop.
     
  4. Steve Fabian

    Joined:
    May 20, 2008
    Messages:
    3,523
    Likes Received:
    4
    That's a loop termination control variable, not a loop execution counter. You do not increment an execution counter before you determine whether or not the loop is to be executed. Test first, increment second. The current report does not tell me how many times the loop was actually executed, e.g., how many lines were read from a file, it tells me how many times it checked whether or not to execute the loop. Depending on how the termination condition is specified, this test count may exceed the number of times the loop was executed. The definition of %_do_loop in HELP -> DO is execution count, not test count.

    The command
    do 0 (echo x) %+ echo %_do_loop
    does not execute the ECHO X command, yet it reports one (1) execution.
     
  5. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,885
    Likes Received:
    29
    Steve, when should the execution count be incremented ... ?

    ... right after the test? Then it would be counted even if the very next statement caused a LEAVE or an ITERATE.

    ... right before the next test (at the end of the loop)? Then it wouldn't be counted if it were after a LEAVE or an ITERATE.

    I can't imagine an implementation that would satisfy everyone all the time. I haven't used any of DO's automatic variables except for testing their function. If I want something counted, I'll count it myself, precisely if and when it should be counted.

    That said, I agree with you (partially ... I think). _DO_LOOP should not be incremented when the body of the loop is not entered.
     
  6. Steve Fabian

    Joined:
    May 20, 2008
    Messages:
    3,523
    Likes Received:
    4
    That's exactly correct. That ITERATE or LEAVE statement is part of the loop. In terms of constructs in C, it ought to be analogous to:
    int _do_loop = 0 ;
    while ( loop execution test ) { _do_loop++ , loop body }


    Notice I do not compare it with the for statement, nor with the FOR of BASIC or DO of FORTRAN. According to the documentation, _do_loop is a pure counter that is independent of repetition control. IIRC that was what was requested for V15. Unfortunately, the FEEDBACK mechanism does not provide access to suggestion history, nor to local copy, so I cannot verify.
     
    #6 Steve Fabian, Sep 23, 2013
    Last edited: Sep 23, 2013
  7. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,885
    Likes Received:
    29
    That has some merit. But what about this (and variations)?
    Code:
    while ( condition ) { body; _do_loop++; }
    There's not a one-size-fits-all.
     
  8. Steve Fabian

    Joined:
    May 20, 2008
    Messages:
    3,523
    Likes Received:
    4
    Vince:
    Your example counts not how often the loop body is executed, but how often the loop body is executed without executing LEAVE - in other words, it depends on the content of the loop body; my way is not.
     
  9. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,885
    Likes Received:
    29
    My point is that none of the alternatives we have discussed may actually count what the user wants counted. That said, I prefer _do_loop **not** being incremented when nothing in the body of the loop is executed.
     
  10. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,885
    Likes Received:
    29
    If I could redesign it, _do_loop would be strictly local to a given DO loop, not existing when a DO loop is finished, and reflecting the status of its immediately-enclosing DO loop. Otherwise, it's just nonsense when there are nested DO loops.
     
    #10 vefatica, Sep 23, 2013
    Last edited: Sep 23, 2013
  11. Steve Fabian

    Joined:
    May 20, 2008
    Messages:
    3,523
    Likes Received:
    4
    How often is any particular program module executed? If it is one of those "single entry - single exit" modules greatly touted under the label "structured programming" in the 70s, it is as many times as it is entered. If a module has a single entry, regardless of how many exits it has the only logical way to count is the number of times it is entered. But under no conditions would I count performing a test before entering the module and never entering it as an execution of the module. Conceptually, the body of a DO loop is a module, and that is the count requested as a V15 enhancement.
    Setting aside the issue of nest DO loops until later, the purpose of the loop counter surviving the ENDDO is to avoid the need to write code to count loop body executions, which could be the character count of a string, of a line or of a file, or the line count of a file, etc., values often required after the loop terminates.

    Exiting nested DO loops
    When LEAVE n was introduced in version 10, the highly useful internal variables reporting various command action counts were not yet invented. In retrospect, a slightly different syntax would have been more genneral. Many HLLs use named loops, allowing the equivalents of both ITERATE and LEAVE to be modified with the name of the outermost loop to be affected (and also allowing a single ENDDO with the specified loop name to be used instead of as many as are nested). The major advantage of named loops over the current LEAVE n syntax is that changing the nesting hierarchy by adding an additional level or removing a level would not always change the outermost level affected. This opens the question what syntax could we use to specify named DO loops? One possibility is a new option, /Z in my example: DO [/Z loopname] ...
    For multilevel flow control dimply append the loop name after the ITERATE, LEAVE or ENDDO, e.g.,
    ENDDO loopname is equivalent to the number of ENDDO statements required to exit from all loops nested inside the named loop and from the named loop.
    How would the action counts of each level be reported? By a 2-dimensional array, one row for each named loop, one column for loop name, and one column for each of _do_loop, _do_errors, _do_dirs, and _do_files. The aray name could be _do_report...
     
  12. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,885
    Likes Received:
    29
    IMHO, that's way over the top. I wouldn't want to deal with it. And I wouldn't be surprised if Rex weren't inclined to go that route. TakeCmd.dll exports Do_Cmd(), suggesting that making all its "automatic" variables "local" (in the C sense) might be reasonable. **Environment** variables will survive after ENDDO; if I want more that that I'll do it myself.
     
  13. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,885
    Likes Received:
    29
    With absolutely no knowledge of the possible pitfalls, I can imagine how it might be done.
    There's one _DO_LOOP, accessible by the user via a global pointer "INT *p_DO_LOOP". Each time a DO loop is entered, it does "INT *pprev_do_loop=p_DO_LOOP; INT my_do_loop; p_DO_LOOP = &my_do_loop;" ... and when exiting a DO loop ... "p_DO_LOOP=pprev_do_loop". I don't know how that would jive with "LEAVE N". If not so well, then maybe a "stack" of pointers to the various my_do_loop INTs might. Maybe it's supposed to do something like that now (but is buggy). It really doesn't make any sense to have one _DO_LOOP being incremented by some arbitrary number of nested loops.
     
  14. rconn

    rconn Administrator
    Staff Member

    Joined:
    May 14, 2008
    Messages:
    9,808
    Likes Received:
    82
    You seem to believe that the DO test is somehow outside of the loop. That is not the case.
     
  15. Steve Fabian

    Joined:
    May 20, 2008
    Messages:
    3,523
    Likes Received:
    4
    Vince:
    I never used LEAVE n, so I agree with you that it would be used far too rarely to make the development effort worth while. This was more an exercise of generalization of the _do_loop[n] construct mentioned earlier.
     
  16. vefatica

    Joined:
    May 20, 2008
    Messages:
    7,885
    Likes Received:
    29
    I don't think I've used LEAVE N, but it's a nice feature. _DO_LOOP[n] was a little tongue-in-cheek.
     
  17. Steve Fabian

    Joined:
    May 20, 2008
    Messages:
    3,523
    Likes Received:
    4
    Well, in the single-line DO the syntax does show it outside:
    do 4 (echo Current loop body execution count: %_do_loop)

    In the the C language all forms of iteration (while, for and do) explicitly separate the statement (or statement block) that is iterated from the iteration controls.That's the manner in which I always thought FOR and DO operate, and the above DO syntax reinforced my interpretation.

    My original request for the _do_loop variable was not absolutely clear, but the intention was for a variable analogous to _do_files when execution control is not from a list of files, but that the two variables just mentioned be equal when found files control execution, i.e., in the code snippet below
    do f in *.btm (REM)
    echo %_do_loop
    echo %_do_files
    the two ECHOs would report the same values - as implemented the former is always 1 more than the latter...

    I had not explicitly requested it, but I am glad the manner in which _do_loop is implemented it is available inside the loop. The two programs where I use it do just that, and do not examine it after the loop is exited, hence my delay of discovering the discrepancy from what I had (not as clearly as possible) asked.
     
  18. rconn

    rconn Administrator
    Staff Member

    Joined:
    May 14, 2008
    Messages:
    9,808
    Likes Received:
    82
    No, it doesn't:

    Code:
    do 4 (echo Current loop body execution count: %_do_loop)
    echo %_do_loop
    
     
  19. Steve Fabian

    Joined:
    May 20, 2008
    Messages:
    3,523
    Likes Received:
    4
    From HELP -> DO:
    "DO WHILE condition evaluates condition each time through the loop as a conditional expression before executing the loop, and will execute it only if it is true. If condition is FALSE when the DO is first executed, the loop will never be executed."

    Let us consider the compound command
    do while 1 lt 0 (echo In loop: %_do_loop) %+ echo After exit: %_do_loop
    According to the documentation in HELP, the LOOP will not be executed at all. When executing the compound command above the only output is, in fact, from the second ECHO, just as the documentation above claims. BUT what _do_loop reports is not zero! It is 1 (one), conflicting with the documentation:
    "%_do_loop The number of times the DO loop has been executed"

    Again, from HELP:
    DO can be used in batch files, aliases, or at the command prompt. To use them in aliases or at the prompt, you need to define the DO on a single line, and enclose the body of the DO loop in a command group following the DO expression. (There is no ENDDO statement in a single-line DO). For example:
    do count=1 to 10 by 1 (echo count=%count)

    Clearly, the loop body is only what is enclosed in the command group, separated from the condition.
    I do not see how displaying the value reported by _do_loop in a command executed AFTER the DO terminates changes the number of times the loop was executed.
     

Share This Page