Subroutines (Part 1)

Subroutines have been my nemesis for some time. Although I generally understand their benefits and purpose, the hows have eluded me in the past. Maybe it was lack of “RTFM”, maybe my early frustration had clouded my perception of the technique. Whatever the reason, I was both giddy with delight and disgusted with my careless ignorance when, on the last day of AppleScript Pro Sessions in Monterey, Shane Stanley was able to switch the light bulb to the “ON” position for me. I will now relate to you my interpretation of that sage advice. A bit of background on subroutines. If you are processing multiple sources of data in the same way at various times within a script, you should cuddle up to subroutines. For example, if your script picks up a list of files from Folder_A and another list from Folder_B. Your script needs to, say, trim the file name extensions from the files in both folders, but do another task to list A and a third to list B. Naturally, this will have you performing the file name trimming twice in your script. Another excellent use of subroutines is to organize and/or break up your script into easier to read and easier to understand parts. This is outlined very well in a recent installment of Stephen Swift’s Mac Observer column, ‘AppleScript: The Macintosh Autopilot’. Click here for ‘Break Your Script Into Pieces with Subroutines’. You may find that a combination of both columns really drives the point home. Insert Twilight Zone music here]

It is also important to note that you don’t necessarily have to perform complex computations or file manipulations in order to reap the benefits of subroutines. In addition, there are a couple of gotchas you should be aware of which often trip up beginners trying to utilize even simple subroutines.

If you are calling a subroutine within another application’s tell block,be sure to insert ‘my’ before ‘theSubroutine()’.

Avoid Subroutine Gotcha #1 Like So

tell application "someapp"
	my theSubroutine()
end tell

on theSubroutine()
	-- dosomething cool here
end theSubroutine

Your subroutine will always return the value generated by the last command in it, so be sure you pay attention to the result. This is often the culprit when a subroutine isn’t doing what you expect. (This is a good time to become familiar with Script Editor’s result window and it will tell you that your subroutine returns true instead of 345,for example.)
Our first example is somewhat abstract, but I believe it to be a downright enlightening illustration of the function of subroutines. (See Figure 1)

Figure 1 - A simple subroutine

set a to 4
set b to 8
set c to 16

duHickeyRoutine(a, b, c)

on duHickeyRoutine(dog, mouse, cat)
	dog + mouse + cat
end duHickeyRoutine

In the first three lines of this script, we set up variables a, b and c with values of 4, 8 and 16 respectively. (See Figure 2) SuperNewbies take note: the arbitrary declaration of variables and assigning values is perfectly logical, so don’t let this throw you. (It took me an embarrassingly long time to understand that AppleScript is just smart and that there isn’t anything magical about declaring variables.)

Figure 2 - Declared variables

set a to 4
set b to 8
set c to 16

The next line is the meat of the script. we’re ‘calling’ the subroutine which is amusingly named ‘duHickeyRoutine’. Within the following parenthesis,we’ve placed our three variables (Figure 3) and, in turn, they contain the values we gave them. (Figure 2)

Figure 3 - Subroutine ‘call’.

duHickeyRoutine(a, b, c)

We are passing 3 values to the subroutine because we’ve set up our subroutine to act upon 3 values, as outlined in the next chunk of our code: the subroutine itself. (See Figure 4) In Figure 4, you can see the subroutine’s variables are named differently. Don’t panic. This is where you will learn another important fact about subroutines. The variables set up for a subroutine within it’s parenthesis (called ‘parameters’) are merely placeholders. Parameters can be named the same as the variables declared at the top of our script (a, b and c) or they can be different. For clarity, I’m naming them differently: dog, mouse and cat. In the second line of our subroutine, we have set up the action we would like for it to perform on its parameters. In this case, a mathematical equation:dog + mouse + cat. This is where it all comes together.

Figure 4 - The subroutine

on duHickeyRoutine(dog, mouse, cat)
	dog + mouse + cat
end duHickeyRoutine

When we call this subroutine (Fig. 3), dog then equals 4, mouse equals 8 and cat equals 16. When duHickeyRoutine does its job, dog + mouse + cat = 28. The total 28 is our ‘result’. We can then proceed back up in our main script body and act on the subroutine’s result, 28. Here’s an example. (Figure 5)

Figure 5 - Simple subroutine and testing result

set a to 4
set b to 8
set c to 16

duHickeyRoutine(a, b, c)
if result is 28 then
	display dialog "It's working!"
end if

on duHickeyRoutine(cat, mouse, dog)
	cat + mouse + dog
end duHickeyRoutine

In Figure 5, we’ve inserted an if/then statement to test for the answer to our subroutine’s equation. Type, compile and run this script in your favorite script editor (ah-ahh-CHOO! Script Debugger). You should get a dialog which looks something like Figure 6.

[center]
Figure 6 - Result/Dialog test[/center]

Let’s have a look at another simple example (Figure 7) In this script, our subroutine rounds a real number. This one should give you a more practical example of how subroutines might be put to use in your own scripts.

Figure 7 - Another simple, but practical subroutine. - by Rob J.

set roundedNum to roundThisNumber(1.57)

on roundThisNumber(numberToRound)
	round numberToRound rounding as taught in school
end roundThisNumber

display dialog roundedNum

As a final note, I have created a flow diagram illustrating our original dog/mouse/cat script. If you’re anything like me, you might grasp these concepts more effectively with a visual aid.

Subroutines Diagram

I’m interested in hearing your thoughts on this edition of unScripted. If you found this helpful, please drop me an email and say so. If you still find yourself in a subroutine pothole, let me know how we might improve this and other code tutorials to help you learn. (“Leave no scripter behind.”, we like to say here at MacScripter) In Subroutines Revealed Part 2, we’ll examine in further detail some of the trappings of subroutine use and expand on the ideas presented here.

Thanks for reading and good luck!