A Subroutine that Calls Other Subroutines by Name.

This is a way to state the name of a subroutine in a normal text string, then send that name to another subroutine whose task is to send data to the named subroutine. The script literally reads itself, looking for subroutines with that name, then executes that subroutine. With this, a single subroutine can manage all the other subroutines in a script, allowing for simplified calls to that one master subroutine.

This is a bare bones example with no restrictions or error handlers. This could loop into trouble if mis-used, but it can also be reigned in easily by restricting what it reads of itself.

Try changing “sub1” to “sub2” in the subToUse variable of line 1 to see it handle another sub.


set subToUse to "sub1"
set msg to "Jello Whirled!"
return doSUB(msg, subToUse)

----------------master sub-----------------
on doSUB(msg, subToUse)
	return run script "return my " & subToUse & "(\"" & msg & "\")" & return & text of document of window 1
end doSUB

----------------other subs-----------------
on sub1(txt)
	set alrt to "''" & txt & "'' was sent to subroutine one."
	say alrt
	return alrt
end sub1

on sub2(txt)
	set alrt to "''" & txt & "'' was sent to subroutine two."
	say alrt
	return alrt
end sub2

Browser: Safari 605.1.15
Operating System: macOS 10.14

Here is an example of a menu that interacts with the ‘master sub’. The menu is simply a list of all subroutines found when the script reads itself. A list of ‘subs to omit’ filters out any subs not suitable for the menu. Not a single “if-then” is required!


set subToUse to word 1 of ((choose from list (showMeSubs())) as text)
set msg to "Jello Whirled!"
return doSUB(msg, subToUse)

----------------menu sub-----------------
on showMeSubs()
	set sbs to {}
	set OMITsubs to {"showMeSubs", "doSUB"}
	repeat with prgs in every paragraph of (text of document of window 1)
		if word 1 of prgs is "on" and prgs contains "(" and prgs contains ")" then
			if OMITsubs does not contain word 2 of prgs then ¬
				set end of sbs to ((characters 4 thru -2 of prgs as text))
		end if
	end repeat
	return sbs
end showMeSubs

----------------master sub-----------------
on doSUB(msg, subToUse)
	return run script "return my " & subToUse & "(\"" & msg & "\")" & return & text of document of window 1
end doSUB

----------------other subs-----------------
on sub1(txt)
	set alrt to "''" & txt & "'' was sent to subroutine one."
	say alrt
	return alrt
end sub1

on sub2(txt)
	set alrt to "''" & txt & "'' was sent to subroutine two."
	say alrt
	return alrt
end sub2


Browser: Safari 605.1.15
Operating System: macOS 10.14

Finally, here is an example offering the user a chance to edit the data to be sent, before it goes to the master subroutine for routing to the chosen sub.


 set msg to text returned of (display dialog "Enter text" default answer "Jello Whirled!")
set subToUse to word 1 of ((choose from list (showMeSubs()) with prompt "send  ''" & msg & "''  to:") as text)
return doSUB(msg, subToUse)

----------------menu sub-----------------
on showMeSubs()
	set sbs to {}
	set OMITsubs to {"showMeSubs", "doSUB"}
	repeat with prgs in every paragraph of (text of document of window 1)
		if word 1 of prgs is "on" and prgs contains "(" and prgs contains ")" then
			if OMITsubs does not contain word 2 of prgs then ¬
				set end of sbs to ((characters 4 thru -2 of prgs as text))
		end if
	end repeat
	return sbs
end showMeSubs

----------------master sub-----------------
on doSUB(msg, subToUse)
	return run script "return my " & subToUse & "(\"" & msg & "\")" & return & text of document of window 1
end doSUB

----------------other subs-----------------
on sub1(txt)
	set alrt to "''" & txt & "'' was sent to subroutine one."
	say alrt
	return alrt
end sub1

on sub2(txt)
	set alrt to "''" & txt & "'' was sent to subroutine two."
	say alrt
	return alrt
end sub2


To give me (and possibly other users) an idea of the situations you might use this technique in, have you had any specific instances where you needed to reference the name of a handler at run-time rather than compile-time ?

Using your first example, you have these few initial lines of code:

set subToUse to "sub1"
set msg to "Jello Whirled!"
return doSUB(msg, subToUse)

But, if I change these lines to this:

set subToUse to sub1
set msg to "Jello Whirled!"
return subToUse(msg)

the outcome is the same, and negates any need to call run script.
You could also do it like this:

set subToUse to sub1
set msg to "Jello Whirled!"
return doSUB(msg, subToUse)

----------------master sub-----------------
on doSUB(msg, subToUse)
	subToUse(msg)
end doSUB

Hi CK,
The idea of a runtime-sub-handler being practical was something that came from two projects;

  1. while cutting and pasting dozens of subroutines into a script to use as a reference tool, I decided it would be easier if the script would just figure out how to call the new subroutines and put them into a ‘choose list’ menu without me having to explicitly enter their names. That reference-tool is in my menubar’s script-folder dropdown as a shortcut that can both demonstrate and display subroutines on the fly. It changes frequently but it’s easy because I tell it to open itself and let it ‘absorb’ a new routine without having to encode it. Similarly, I can remove a subroutine and it automatically stops offering that sub in the menu. No if-thens to tidy-up.

  2. is an ongoing project that involves having scripts ‘write themselves’. Basically it was a way for a group of scripts to find subroutines in each other and see if they were a good fit to be shared. I have some of my robotics students who argue strongly that I should not refer to it as ‘Artificial Intelligence’ since no learning actually occurs. Rather, it gives the ‘appearance’ of making decisions. We jokingly call it AAI; ArtificialArtificialIntelligence The next version also interprets any parameters that are passed without being explicitly defined. That’s trickier!

These are not techniques that lend themselves to a single, well defined task. But for larger, more fluid interactivity between scripts, this offers great freedom!

Model: Mac Pro, Yosemite
AppleScript: 2.7
Browser: Safari 601.2.7
Operating System: macOS 10.14