Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!

Single-line DO inside nested multi-line DOs?

May
12,845
164
The BTM below is contrived to be fast and make a point. It's outer 2 nested DO loops make it count from from 1 to 4. If it's inner (nonsense) DO loop is replaced by a single-line DO, the BTM only counts to 2 (terminating when the outermost DO loop should iterate).

Code:
setlocal
set count=0
do q=1 to 2
do r=1 to 2

::do i=1 to 2 ( set a=a )
do i=1 to 2
    set a=a
enddo

set /a count+=1
echo %count

enddo
enddo
quit
 
TCC 14.02.40 Windows XP [Version 5.1.2600]

I tested a the variant below, which differs from the inline version of the original by adding more ECHO statements to monitor progress, and using a progress monitoring ECHO in the inline DO instead of the "nonsense statement set a=a".
Code:
   1 : @echo off
   2 : setlocal
   3 : set count=0
   4 : echo line %_batchline
   5 : do q=1 to 2
   6 : echo line %_batchline
   7 :   do r=1 to 2
   8 :     echo line %_batchline
   9 :       do i=1 to 2 ( echo line %_batchline count=%count q=%q r=%r i=%i )
  10 :     set /a count+=1
  11 :     echo line %_batchline count=%count q=%q r=%r
  12 :   enddo
  13 :   echo line %_batchline count=%count q=%q
  14 : enddo
  15 : echo line %_batchline
  16 : quit


This is the redirected output:
line 4
line 6
line 8
line 9 count=0 q=1 r=1 i=1
line 9 count=0 q=1 r=1 i=2
line 11 count=1 q=1 r=1
line 8
line 9 count=1 q=1 r=2 i=1
line 9 count=1 q=1 r=2 i=2
line 11 count=2 q=1 r=2
line 15



I then replaced the inline DO with a normal DO:
Code:
   1 : @echo off
   2 : setlocal
   3 : set count=0
   4 : echo line %_batchline
   5 : do q=1 to 2
   6 : echo line %_batchline
   7 :   do r=1 to 2
   8 :     echo line %_batchline
   9 :       do i=1 to 2 
  10 :         echo line %_batchline count=%count q=%q r=%r i=%i
  11 :       enddo
  12 :     set /a count+=1
  13 :     echo line %_batchline count=%count q=%q r=%r
  14 :   enddo
  15 :   echo line %_batchline count=%count q=%q
  16 : enddo
  17 : echo line %_batchline
  18 : quit


This is the output of the second version:

line 4
line 6
line 8
line 10 count=0 q=1 r=1 i=1
line 10 count=0 q=1 r=1 i=2
line 13 count=1 q=1 r=1
line 8
line 10 count=1 q=1 r=2 i=1
line 10 count=1 q=1 r=2 i=2
line 13 count=2 q=1 r=2
line 15 count=2 q=1
line 6
line 8
line 10 count=2 q=2 r=1 i=1
line 10 count=2 q=2 r=1 i=2
line 13 count=3 q=2 r=1
line 8
line 10 count=3 q=2 r=2 i=1
line 10 count=3 q=2 r=2 i=2
line 13 count=4 q=2 r=2
line 15 count=4 q=2
line 17


Comparison of the two outputs shows that the inline DO somehow interferes with the outermost loop, and causes it to terminate after the first iteration. I also changed all loop upper limits from 2 to 3, and once again the outermost (DO q) loop terminated short. I also determined that ensuring whitespace between the loop control variable name and the equal sign = and between the sign and the start value has no effect.

Rex, I suggest the documentation of the single line DO should have a subtitle, and the grouping parentheses be referred to as "left parenthesis (" etc. for clarity. Not all screens display the boldness of ( distinctively.
 
The BTM below is contrived to be fast and make a point. It's outer 2 nested DO loops make it count from from 1 to 4. If it's inner (nonsense) DO loop is replaced by a single-line DO, the BTM only counts to 2 (terminating when the outermost DO loop should iterate).

I will change the help to make it clearer that single-line DO's are not supported in batch files, and that they cannot be nested. (I would have banned them entirely in batch files, but I was worried about people defining them in aliases and then referencing the alias in a batch file.)
 
A brief test showed that the problem isn't with the single-line do nested in non-single-line DO's, but with the (unnecessary) QUIT combined with the single-line DO nested in multiple non-single-line DO's.

Since this isn't a supported use, and it provides no benefit (and several drawbacks), and since the workaround is to use the documented format, I'm inclined to think it's not worth tearing the parser apart (and breaking other things) to try to support it.
 
A brief test showed that the problem isn't with the single-line do nested in non-single-line DO's, but with the (unnecessary) QUIT combined with the single-line DO nested in multiple non-single-line DO's.

Since this isn't a supported use, and it provides no benefit (and several drawbacks), and since the workaround is to use the documented format, I'm inclined to think it's not worth tearing the parser apart (and breaking other things) to try to support it.
It may not be worth tearing the parser apart but it does provide the benefit of speed, especially when doing small things many, many times.
Code:
v:\> type docompare.btm
timer
do i=1 to 100000 ( set a=0 )
timer
 
timer
do i=1 to 100000
        set a=0
enddo
timer
 
v:\> docompare.btm
Timer 1 on: 10:53:58
Timer 1 off: 10:54:08  Elapsed: 0:00:09.80
Timer 1 on: 10:54:08
Timer 1 off: 10:54:25  Elapsed: 0:00:16.83
 
I will change the help to make it clearer that single-line DO's are not supported in batch files, and that they cannot be nested. (I would have banned them entirely in batch files, but I was worried about people defining them in aliases and then referencing the alias in a batch file.)
In a simple test outside a batch file, nesting seems OK.

Code:
v:\> do i=0 to 1 ( do j=0 to 1 ( do k=0 to 1 ( echo %i %j %k ) ) )
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
 
I don't understand how a QUIT command, which is past the outermost ENDDO Replacing QUIT with EXIT (which may be necessary) in the last line the output was identical.

I tried another version, no QUIT command, no aliases, one more loop, updating COUNT inside single line DO :
Code:
   1 : @echo off
   2 : setlocal
   3 : unalias *
   4 : unset *
   5 : set count=0
   6 : echo line %_batchline count=%count
   7 : do q = 1 to 3
   8 : echo line %_batchline
   9 :   do r = 1 to 3
  10 :     echo line %_batchline
  11 :     do s = 1 to 3
  12 :       echo line %_batchline
  13 :         do i = 1 to 3 ( set /a count+=1 %+ echo line %_batchline count=%count q=%q r=%r s=%s i=%i )
  14 :       echo line %_batchline count=%count q=%q r=%r s=%s
  15 :     enddo
  16 :     echo line %_batchline count=%count q=%q r=%r
  17 :   enddo
  18 :   echo line %_batchline count=%count q=%q
  19 : enddo
  20 : echo line %_batchline count=%count

Surprise!!! the ECHO in line 16 is never reported! But line 20 reported 3 times... Seems that using a single-line DO in a batch file mixes up the parser, it executes a command outside of an enclosing DO instead of inside.

It seems to me that the single line DO confuses the part of the parser which keeps track of loop ends of the already parsed batch file, possibly by searching for ENDDO. As fas as I am concerned, prohibiting "single line DO" in batch files, and reporting them as errors if used is OK.
 
It may not be worth tearing the parser apart but it does provide the benefit of speed, especially when doing small things many, many times.

Not really; running your test here shows:

Code:
Timer 1 on: 12:23:00
Timer 1 off: 12:23:05  Elapsed: 0:00:04.57
Timer 1 on: 12:23:05
Timer 1 off: 12:23:12  Elapsed: 0:00:06.20

The parser changes necessary would eat up most of that difference (and also make *all* DO's significantly slower). Plus the inability to debug single-line DO's means the time you spend trying to debug anything other than the most trivial DO will probably be several orders of magnitude greater than the time savings in running the batch file for the rest of your life.
 

Similar threads

Back
Top