UserLand Software
Powerful, cross-platform web scripting.
 

Loops, Variables, Parameters, and Conditionals

Frontier Scripting Tutorial

About This Tutorial

What Does Frontier Do?

Keywords, Handlers, Verbs, and Calls

Loops, Variables, Parameters, and Conditionals

The Handler Rule

Returns, Addresses, and Dereferencing

Scope and With

Strings and Files

Outlines and Tables

Running, Debugging, and Getting Help

Datatypes

A Real-Life Problem

String Parsing and Substitution

Manipulating Files and Folders

Final Touches

Repeating, repeating...

As mentioned in the previous chapter, our counting routine works but is a bad example of programming.

The program contains a clear patterned repetition, and in cases of this sort scripting languages generally provide some method of reducing the code to the pattern alone, letting the computer perform the repetition.

You do see the pattern, right? At every step we are saying:


msg (n)
clock.waitseconds (1)

where by "n" I mean "some number".

Not only that, but there is a pattern to what "n" is: at every step it is larger by 1 than at the previous step. There are many ways in Frontier to create the loop we want, but here is one of the most obvious:


on Counter ()
   for n = 1 to 10
      msg (n)
      clock.waitseconds (1)
Counter ()

Try running this. It has exactly the same effect as our original script; we have reduced a twenty-line script to three lines, and we have eliminated for ourselves a great deal of work (and possible sources of error) by letting Frontier do the work of calculating what each successive number should be.

For... loops

The first line of the script uses "for," a keyword introducing a looping structure.

In a looping structure, everything inside the loop is repeated again and again before proceeding to whatever comes after the looping structure; and, as with a handler definition where we indent the actual handler below the "on" line, here we let Frontier know what is inside the loop by indenting that material below the line that introduces the loop (in this case, the "for" line).

The "for" structure involves the use of a variable, which we have called "n". A variable is a named value (rather like a database entry).

We can call the variable in a "for" line anything we like, but once we have chosen a name for it we must be consistent; having called the variable "n" in the "for" line, we must refer to it as "n" within the repeated material.

The "for" line says: repeat the material of the loop again and again, and when you do, let the variable "n" take on a new value each time, starting with 1, incrementing the value each time, and stopping the loop after the value 10 has been used.

Within the loop itself, we display the value of "n" in the About Window and pause for one second; since the value of "n" is 1 the first time through the loop, and is one more each time through the loop than it was the previous time, and is 10 the last time through the loop, the effect is exactly that of displaying the numbers 1 to 10.

Our counting verb, Counter, is now considerably more elegant; but at this point we might decide that it also unnecessarily specific. One of the goals of good programming is to write routines that are of general utility.

Our counting verb is frozen, as it were, into counting from 1 to 10; it cannot count from 1 to 20, or from 10 to 15. We have "hard-coded" the limits 1 and 10 into our definition of Counter. How might we fix this?

Asking for a parameter

Let's begin by thinking how to remove the restriction that what we are counting up to is 10. Let's make it so that we can count from 1 to any number at all.

To do this, we need to replace "10" by a variable, because at the time we write the code we don't actually know how high Counter is to count. Let's call the variable "upperLimit":


on Counter ()
   for n = 1 to upperLimit
      msg (n)
      clock.waitseconds (1)
Counter ()

But if we try to run this script, we get an error; we have not told Counter how to know, at the time that it runs, what "upperLimit" is to be. Where should the value for "upperLimit" come from?

One answer is that it might be passed to Counter as a parameter. To make this be so, simply use "upperLimit" as the name of Counter's parameter in its definition, like this:


on Counter (upperLimit)
   for n = 1 to upperLimit
      msg (n)
      clock.waitseconds (1)
Counter ()

The "on" line here says: I define a verb Counter, and whenever Counter is called it should be handed one parameter. Take the value of that parameter and assign it to a variable called "upperLimit".

Thus, when we get to the "for" line, "upperLimit" has a value, namely, the value handed to Counter as a parameter when the call was made.

Of course, this means that we actually must remember to hand Counter a parameter. If you run the script as written above, you get an error (try it); we have defined Counter to require one parameter, but when we actually come to call Counter, in the last line, we have forgotten to supply a parameter.

So let's supply one; let's supply 5. Modify the last line accordingly, and run the script:


on Counter (upperLimit)
   for n = 1 to upperLimit
      msg (n)
      clock.waitseconds (1)
Counter (5)

It works. Or, we might supply 20; change the last line again, and run the script:


on Counter (upperLimit)
   for n = 1 to upperLimit
      msg (n)
      clock.waitseconds (1)
Counter (20)

It works again.

Default parameter

Now, here's an interesting twist. A further extension of the power of parameters is to supply a default value for a parameter. This means that in the case where the caller fails to supply a value for that parameter, the handler supplies one instead.

Thus, we could set up Counter so that it counts from 1 to whatever number is supplied as a parameter when the call is made, but in case no parameter is supplied at all, we'll count to 10. The way to code this is to assign the default value in the "on" line, like this:


on Counter (upperLimit = 10)
   for n = 1 to upperLimit
      msg (n)
      clock.waitseconds (1)
Counter (20)

If you press the Run button to run this script, Counter counts to 20 as before. But if you change the last line so that no parameter is supplied when the call is made:


Counter ()

then when you run the script, there is no longer an error; instead, Counter counts to 10, the default case.

Asking for two parameters

Let's generalize Counter still more, so that we not only count to any number the caller cares to supply, but also from any number.

We'll need another variable to represent this - let's call it "lowerLimit" -- and let's give that variable its value by handing it in as a parameter, just as with "upperLimit", and give that parameter a default value of 1.

Multiple parameters are signified by separating the parameters with commas:


on Counter (lowerLimit = 1, upperLimit = 10)
   for n = lowerLimit to upperLimit
      msg (n)
      clock.waitseconds (1)
Counter ()

If we run this script, Counter counts from 1 to 10. But if we change the last line to:


Counter (2, 6)

then Counter counts from 2 to 6. If we call Counter with just one parameter, it is taken to be the first parameter; so, for instance, if we change the last line to:


Counter (5)

then Counter counts from 5 to 10.

It is also possible to supply only the second parameter; to do this, we have to say by name what parameter we're supplying. For instance, we can change the last line to:


Counter (upperLimit: 5)

and Counter counts from 1 (the default) to 5 (the parameter we fed it).

Finally, we can generalize Counter even further, to allow our starting number to be bigger than our ending number.

At the moment, this is not an error, but no counting is performed; if you change the last line to:


Counter (6, 4)

then no error message appears, but nothing else happens either. This is because it is not an error for a "for...to" to have its first number be larger than its second, but in such a case the "for...to" never performs its loop.

If a "for" loop is to decrease its number by 1 on each loop instead of increasing it, it must be written as a "for...downto" loop instead.

So we need Counter to make a choice: if the first parameter is smaller than the second parameter, then we should count up as we are doing already, but if the first parameter is larger than the second parameter, we should count down.

Conditionals

Choices of this sort are indicated by use a conditional structure. The basic conditional structure in Frontier is "if"; when there two alternatives it is often simplest to use this in the form "if/else".

Once again, the work that is to be done in each case, the "if" case and the "else" case, is indicated by indenting the corresponding instructions below the "if" and the "else", respectively.

So we can rewrite Counter like this:


on Counter (lowerLimit = 1, upperLimit = 10)
   if lowerLimit < upperLimit
      for n = lowerLimit to upperLimit
         msg (n)
         clock.waitseconds (1)
   else
      for n = lowerLimit downto upperLimit
         msg (n)
         clock.waitseconds (1)
Counter ()

Try running this with the last line consisting of Counter (1,3) and Counter (5, 2) and see what happens.

Experiment with other numbers. What happens if one of the parameters is negative? What happens if one of the parameters is not an integer? What happens if one of the parameters is the word "haha" (in quotes)?

PreviousNext

   

Site Scripted By Frontier © Copyright 1996-98 UserLand Software. This page was last built on 2/10/98; 1:26:14 AM. It was originally posted on 4/15/97; 8:53:07 PM. Webmaster: brent@scripting.com.

 
This tutorial was adapted for Frontier 5 by Brent Simmons, from the Frontier 4 scripting tutorial written by Matt Neuburg.