mScriptBox Tutorial
Introduction to Loops

Written by B0P
Published with permission.

Table Of Contents

  1. Introduction
  2. What are loops?
  3. How does it work?
  4. GOTO Loops
  5. WHILE Loops
  6. Lockups
  7. Speed
  8. Conclusion

1. Introduction  Back to Top

Welcome to this little article on one of mIRC scripting's most useful features, the ability to loop.

Prerequirements for this article is knowledge of IF-THEN-ELSE, aliases, identifiers and variables.


2. What are loops?  Back to Top

A loop is a piece of code that repeats itself for as long as we decide, the end or the beginning of the loop has instructions that causes the loop to know when it should jump to the beginning of the loop's code, and repeat once more.

Without loops, it's unlikely that computers and programming would have come very far. Let's look at a simple alias that lists all channels you're on. First without the use of loops:

alias chlist {
  echo -a I'm on $chan(0) channels:
  IF ($chan(1) != $null) { echo -a Channel 1 is $chan(1) }
  IF ($chan(2) != $null) { echo -a Channel 2 is $chan(2) }
  IF ($chan(3) != $null) { echo -a Channel 3 is $chan(3) }
  IF ($chan(4) != $null) { echo -a Channel 4 is $chan(4) }
  IF ($chan(5) != $null) { echo -a Channel 5 is $chan(5) }
  IF ($chan(6) != $null) { echo -a Channel 6 is $chan(6) }
  IF ($chan(7) != $null) { echo -a Channel 7 is $chan(7) }
  echo -a End of channel listing
}

Then the same command with a WHILE loop:

alias chlist2 {
  VAR %max = $chan(0), %c = 1
  echo -a I'm on %max channels:
  WHILE (%c <= %max) {
    echo -a Channel %c is $chan(%c)
    INC %c
  }
  echo -a End of channel listing
}

If you've got mIRC 5.70 or above, you can use the WHILE loop'd code in chlist2 instead of chlist, which hardcodes everything. Even if you use an earlier version than 5.70, you can still loop, using GOTO loops. I'll get back to this later on, for now let's quickly observe the main advantage with loops: FAR smaller code.


3. How does it work?  Back to Top

The technique of looping takes advantage of dynamic elements in code such as variables and identifiers, looking at the earlier examples, all the lines in the listing was equal except for the numbers 1 - 7. Loops are ideal for purposes like listing or performing a line of functions that are almost exactly similar.

Wether you use WHILE loops or the older form, GOTO loops, the starting point of a loop is an IF statement that determines how long the loop will run. Let's look at both forms of loops a little closer.


4. GOTO Loops  Back to Top

For years this was the only option for mIRC scripters to create loops, and because mIRC scripting is what it is, GOTO loops are still used by some people.
The syntax of a GOTO loop is as follows:

header {
  <some code>
  <some more code>
  :target
  IF (if statement) {
    commands to perform per re-iteration
    INC %counter
    GOTO target
  }
  <some code>
  <some more code>
}

The key elements here is the :target, the IF statement, the INC %counter and the GOTO target. The :target is literally a target in the code that can be reached by using the GOTO command, the IF statement is what will eventually stop the loop from reiterating, and the INC %counter is the command that gives dynamic to the loop. Let's see how the example from above would look using a GOTO loop.

alias chlist3 {
  VAR %max = $chan(0), %c = 1
  echo -a I'm on %max channels:
  :top
  IF (%c <= %max) {     echo -a Channel %c is $chan(%c)
    INC %c
    GOTO top
  }
  echo -a End of channel listing
}

As we see, not that different. The :top target is the starting point of the loop (note that the line above only is showed once, thus it's not in the loop), aside from specifying the target and using goto top at the end of the loop, all the lines are similar to a WHILE loop. Each :target must be unique for the alias/popup/remote that called it, meaning if we wanted another loop within the loop in chlist3, we would need to call the target something else, for instance :top2. Also note that while we specify the target's location in the code with :targetname, we use only goto targetname (without the colon) when using /goto to jump to that target.

GOTO loops is what you have to settle for if you're using mIRC 5.61 or earlier, but for mIRC 5.70 and newer we have a better tool, the WHILE loop, which we explain below.


5. WHILE Loops  Back to Top

We have already seen the WHILE loop in action, in our channel listing alias, chlist2.
The syntax for a WHILE loop is as follows:

header {
  <some code>
  <some more code>
  WHILE (if statement) {
    commands to perform per re-iteration
    INC %counter
  }
  <some code>
  <some more code>
}

The key elements in a WHILE loop is the WHILE statement itself and the inc %counter. The WHILE statement is a regular if-then-else statement and indicates the start of the loop, as well as determines when the loop should end. Inc %counter increases the control variable and allows us to measure the progress of the loop.

Let's look at an example again, this time we'll look at an alias that colors nicknames in a channel according to their status.

alias ncol {
  VAR %max = $nick(#,0), %c = 1
  WHILE (%c <= %max) {
    IF ($nick(#,%c) isop #) {       cline 4 # $nick(#,%c)     }
    ELSEIF ($nick(#,%c) isvo #) {       cline 5 $nick(#,%c)     }
    IF ($nick(#,%c) == $me) {       cline 3 $me     }
    INC %c
  }
}

The first line initializes the variables we'll use in the alias, the WHILE is a simple if statement that stops the loop when the counter variable %c becomes larger than %max, which is the number of nicks in the channel. The body of the loop consists of 4 lines, line 1 colors the current nickname red if he/she is an op in the channel, line 2 colors the nick brown/dark red if he/she is a voice, line 3 colors your own nick green, and line 4 increases the counter variable %c.

Simple, isn't it? =) If we wanted to do this without loops, we would have to write an alias that would be somewhere around 50-100 lines long, just to ensure we had midsized channels accounted for, many channels have more than 100 users and our massive alias wouldn't work fully for these channels. With a loop, you don't have to worry about how many users are in a channel, but only about writing an effective loop to perform the tasks you need as quickly as possibly.


6. Lockups  Back to Top

There's a few things to note when using loops. First, things will go wrong. You will always encounter problems where a variable doesn't evaluate as you think it should, and the loop will never know when to stop, you've got a so-called Infinite loop. If this happens, your mIRC will lock up, but fear not! For see, press CTRL+Break (the break key is usually located at the top right of most keyboards, aside the scroll lock key), and mIRC will break out of the endless loop.

The most common reason for an infinite loop is that you forget to /inc the counter variable, which means the if statement always will be true. If you should get an infinite loop, your best tip is to look at the if-then-else statement and ensure that you are modifying the counter variable.

Another thing regarding loops; sometimes they just plainly take a long time to finish executing. In some cases, several minutes. And while the loop is executing, mIRC may lock up. This is not a problem if the loop takes only a few miliseconds to finish, but if it takes minutes, you risk that your mIRC session is busy doing the loop and won't reply to the server's PING, with a result that you get disconnected because the IRC server thinks you're no longer connected.

To prevent this, you can either try to use faster routines, or you may run an extra mIRC session just for the purpose of performing the loop, and close it once the loop finishes. This way the mIRC session that's connected to IRC will be free to do it's normal tasks.


7. Speed  Back to Top

I've tested the speed of both GOTO and WHILE loops with 2 simple aliases as follows:

alias gspeed {
  VAR %s = $ticks, %c = 1, %max = $1
  :top
  IF (%c <= %max) {     INC %c
    GOTO top
  }
  echo -a Ended GOTO loop after %max runs, in $calc($ticks - %s) ticks
}

alias wspeed {
  VAR %s = $ticks, %c = 1, %max = $1
  WHILE (%c <= %max) {     INC %c
  }
  echo -a Ended WHILE loop after %max runs, in $calc($ticks - %s) ticks
}

Usage is /gspeed N or /wspeed N where N is the amount of loops to perform. Note that this test only tests the speed of increasing the counter and continuing the loop, the loop does not perform any commands as given here. With 3 test values, 1,000, 10,000 and 100,000 reiterations, the results were as follows (average of 3 runs, amount is in ticks (1,000 ticks is 1 sec)):

  1,000 10,000 100,000
GOTO
140
1545
15649
WHILE
126
1348
13681

The results suggest that for these rather useless loops, WHILE loops are faster than GOTO loops, as much as 2 seconds faster on 100,000 reiterations. There are many facts to consider when determining speed, so results for loops that actually performs any commands may vary from this test, however WHILE loops will still be the faster way.


8. Conclusion

In this article we've been exploring the advantages to using loops, as well as looking closer at the various types of loops, what can we read from all this?

First off; using loops is next to always the easiest and fastest way to perform listings or multiple similar commands at, as the results above show, around 1-2 seconds for 10,000 runs of a loop, that's not bad ;)

Second; WHILE loops are faster and smaller in code than GOTO loops. Thus, WHILE loops should always be used if your mIRC version is newer than 5.70 and you are not worried about backwards compatibility in your script. If you need your script to be compatible with earlier versions of mIRC, you will need to use GOTO loops.

The real trick to mIRC scripting and programming in general is as much to be able to see what tool is the right at what place, hopefully with this article you have gotten a more intimate knowledge of loops and can start applying this knowledge to scripting problems you face :)