This time out, we’ll dig a bit deeper into the mystery that is subroutines. Specifically, we’ll focus on the ways in which a scripter might return results from a subroutine back to a primary script as well as look at some of the pitfalls and gotchas which often arise when beginners use subroutines.
Returning Results - The Output of Our Machine
Think of subroutines as little machines within your scripts which do specialized jobs. Something like a toaster or a blender in your kitchen. A subroutine might look at the total of a mathematical equation and make a decision; just like a toaster turns bread golden brown and ready for buttering, but it’s just one part of your complete breakfast. In the following example, we’re using a subroutine to look at a sum total and tell the primary script whether or not the total is greater than 10. Simple, but enlightening.
Our Exercise Script
set a to 2 set b to 5 set c to 8 set theTotal to (a + b + c) greaterThanTen(theTotal) if result is true then display dialog "theTotal is greater than 10!" end if on greaterThanTen(someNumbers) if someNumbers > 10 then return true else return false end if end greaterThanTen
Let’s break it down.
First, in Fig. 1, we have declared three variables as numbers we plan to add together.
Figure 1. - Declaration of number variables
set a to 2 set b to 5 set c to 8
In the second portion of our example (Fig. 2) we’re doing something which may be new to beginners: setting a variable to an equation. Don’t let this throw you. In this case, we’re adding the three variables we declared in figure one together and telling our script to set ‘theTotal’ to whatever the result of the a+b+c equation is. Based on the values we gave a, b and c in the previous lines, our variable ‘theTotal’ equals 15.
Figure 2 - Setting up a variable to an equation
set theTotal to (a + b + c)
In Fig. 3, we’re ‘calling’ the subroutine. This is where your cereal stays crunchy in milk, a very important lesson. To refer back to part 1 of this tutorial, this subroutine call is made up of two important elements. (If your subroutine call appears within a tell block or statement, insert the word ‘my’ before the call. For now, don’t worry about why so much as it is a necessary part of calling a subroutine which lives elsewhere in the script and outside your active tell block.) The first is the name of the subroutine. Notice the name I’ve given it: ‘greaterThanTen’. That should give you a hint as to what we’re going to have the subroutine do. In this case, the subroutine is going to decide whether or not ‘theTotal’ is greater than 10. This is the actual call itself. The second part of our subroutine call, within the perenthesis, is the subroutine’s parameter; a variable we’re ‘passing’ to our virtual toaster. (More complex subroutines can and likely will have multiple parameters within those perenthesis.) Liken ‘theTotal’ to our bread to be toasted.
Figure 3 - The subroutine ‘call’
Now, we’re going to jump down to the actual subroutine because this will be the order in which our script executes the commands we have written. Stay with me and freshen that glass of orange juice.
Figure 4 - The subroutine
on greaterThanTen(someNumbers) if someNumbers > 10 then return true else return false end if end greaterThanTen
In Fig. 4, we have the subroutine’s general makeup. Remember, the variable within perenthesis in this portion is merely a placeholder. We can name this anything we please because by calling this subroutine and passing it ‘theTotal’ in the previous step (Fig. 3), we’re merely telling it to use ‘theTotal’ in place of ‘someNumbers’ during this call.
Proceeding into the subroutine, we are now testing whether or not ‘someNumbers’ (Which, in this case, is filled with ‘theTotal’) is greater than the number 10. If it is, we’ll return true; as in, the value of someNumbers is greater than 10. If it is not, we’ll return false; as in, the value of someNumbers is not greater than 10.
Important note: Whatever we RETURN from the last command in the subroutine (lines 3 and 5 in Fig. 4) is defined as the subroutine’s RESULT.
Figure 5 - Using the subroutine’s result
if result is true then display dialog "theTotal is greater than 10!" end if
Finally, in Fig. 5, we’re acting on the result of the subroutine to execute our final command. In this case, if the result of our subroutine ‘greaterThanTen’ is true, a dialog will be displayed. Note that in this example, command order, as always, is key. When we said ‘if result is true.’, the script assumes we mean the result of the command just before it. The result of the subroutine call; the value we told the subroutine to return. Hence, the result of our subroutine is, in fact true, so our dialog will display.
Muffin Burner #1: One common mistake is to forget that the last command in the subroutine is its result. If your script isn’t working or is erroring out using a subroutine, be sure to check that your subroutine returns what you expect as its result. Check that subroutine’s last command. (See Fig. 6) In the example below, we’ll never get a dialog to display because our result test (line 6) is testing that the result of our subroutine is a number (7), but we’ve set up our subroutine to return a boolean value, ‘true’.
Figure 6 - Check that last subroutine command
set varBlue to 3 set varGreen to 9 set varYellow to 8 set theColors to (varBlue + varGreen + varYellow) testRoutine(theColors) if result is 7 then display dialog "yeah!" end if on testRoutine(someStufftoProcess) if someStufftoProcess = 20 then return true -- woops! end if end testRoutine
Muffin Burner #2: Another often-made mistake is to leave out the parenthesis. Although one may use subroutines as an organizational tool for breaking up scripts into manageable chunks without necessarily processing data, you’ll still need to use the perenthesis at the subroutine itself, even if you aren’t passing parameters or values between the two. (See Fig. 7) The call works properly without the perenthesis, but it’s a good idea to keep them in there as well for clarity. Just make yourself stay in the habit. Without the perenthesis on the subroutine call, it looks like any other variable and you may become confused when referring to the code later.
Figure 7- Don’t forget the parenthesis
testRoutine() on testRoutine() display dialog "My subroutine is working!" end testRoutine
By now, you are likely able to start writing your own subroutines. Keep these caveats in mind and get yourself subscribed to one or more AppleScript email lists, if you find yourself stuck in the process. Or exploit the great resources here at MacScripter.
In a matter of a few scripts, you’ll have all sorts of grrrreat subroutines to fill your daily nutritional requirements.
Be well and thanks for reading.