How to Loop the Loop

HelpFile Links :   Label | IfNotWindowOpenGotoLetIfGotoRepeatUntilReadFileSeparateWhileEndWhileDayOfWeekHour

Related link : Avoiding Tight Loops

What's a Loop?

A loop is a sequence of instructions that is continually repeated until a specific condition is reached - or infinitely (until the user terminates the script).

  Comic by Bill Amend. Original Source

In Macro Scheduler there are three looping constructs:

  1. Using a Label and a Goto statement
  2. Using Repeat and Until
  3. Using While and EndWhile

A loop may have conditional logic in it to decide whether the loop should continue or not.

Using Label and Goto

Here's a really simple never-ending (infinite) loop:

Label>start
  // do something here
Goto>start

Hopefully that is self explanatory and doesn't need much saying about it.  The Label statement marks a point in the script.  The Goto statement causes execution to jump to the specified label. So in the above the script simply does the "// do something here bit" over and over and over again (until you stop the script or shut down the PC!).

Now, supposing you wanted to loop until a specific condition, say a specific window exists.  You could do:

Label>start
  // do something here
  IfNotWindowOpen>Untitled - Notepad
    Goto>start
  Endif

So here all we're doing is only jumping back to start if the "Untitled - Notepad" window does NOT exist.

Or let's say you wanted to repeat the loop only 5 times.  You could do:

Let>k=0
Label>start
  Let>k=k+1
  // do something here
  If>k<5
    Goto>start
  Endif

Here we have a loop counter "k" which we increment (add 1 to) in every iteration.  At the end we check to see if k is less than 5 and if so we loop back.  So the loop would stop when k reached 5.  This is a rather clunky way of waiting 5 times and many real programmers  hate goto statements, so a neater way is to use Repeat/Until which we'll look at next.

Using Repeat and Until

With Repeat/Until our "loop only 5 times" example becomes:

Let>k=0
Repeat>k
  Let>k=k+1
  // do something
Until>k=5

It's a bit neater, reads better and avoids the "spaghetti" code thing that overuse of Gotos could create. But at the end of the day the choice is yours.

Instead of a fixed number like 5 you might be looping through something dynamic like the lines in a text file or rows in Excel, and your Until condition would be checking for the loop counter becoming equal to the number of lines/rows:

ReadFile>c:\temp\test.txt,fileData
Separate>fileData,CRLF,lines
Let>k=0
Repeat>k
  Let>k=k+1
  Let>this_line=lines_%k%
  //do something
Until>k=lines_count

Using While and EndWhile

With While/EndWhile we could replicate the "loop 5 times" loop:

Let>k=0
While>k<5
  Let>k=k+1
  // do something
EndWhile

The most noticeable difference is that we check the condition at the top of the loop.  That's why in the example above the condition is k<5. Try stepping through the code  with the debugger to see why that is.

Here's how we might implement our "Check for Untitled - Notepad" loop with a While/EndWhile:

Let>NotepadOpen=FALSE
While>NotepadOpen=FALSE
  IfWindowOpen>Untitled - Notepad
    Let>NotepadOpen=TRUE
  Else
     // do something
  Endif
EndWhile

While can take a "complex expression" as well.  That's one with a combination of conditions, e.g. let's say we want to loop only if it is Monday morning:

DayOfWeek>day
Hour>hh
While>{ (%day% = 2) AND (%hh% < 12) }
  //do something
  DayOfWeek>day
  Hour>hh
EndWhile

Confused? The DayOfWeek function returns the day number where 1 is a Sunday. So Monday is 2. If it's in the morning the hour must be less than 12. So our Loop condition must be "day is 2 AND hour is less than 12".

Breaking out of Loops Prematurely

Best practice is NOT to break out of a loop but you could jump out of one simply by using a Goto and Label.  You might set a label after your loop and have an If/Endif condition inside the loop which uses a Goto to jump to the label if your exit condition turns true. 

Remember, many hardcore geeks go a bit off colour if they see too many Gotos and if you're going to use an If/Endif anyway why not just set the loop condition to true and nest the code within your loop instead? We did exactly that in our While/EndWhile "Check for Untitled - Notepad" loop above.

Avoid Tight Loops

To keep the examples clear I haven't done so here but it's always worth adding a delay inside your loops.  Here's an explanation as to why.

Still need help? Contact Us Contact Us