Are lists of handlers possible?

I want to do something like:

on input(theString)
set thisList to {“this text”, “that text”, “the other text”}
tell application “Ircle” to set x to match theString with thisList
– the above part works. “match is in Ircle’s applescript dictionary” below is where I have problems
set theFunctions to {thisFunction(),thatFunction(),theOtherFunction()}
set doFunction to item x of theFunctions
doFunction
end input

on thisFunction()
–do some stuff
end thisFunction

on thatFunction()
–do some stuff
end thatFunction

on theOtherFunction()
–do some stuff
end theOtherFunction

is this even possible? If so how does the correct way to do it differ from what I have above?

What I have above produces and error “<> doesn’t understand the thisFunction message.”

I assume you want to make a list of handlers and then choose which one to run, right?

I’m not sure if that is possible in a clean way.

Your code.

set theFunctions to {thisFunction(),thatFunction(),theOtherFunction()}

.looks like it makes a list of handlers, right?

But actually it makes a list of the results of the handlers.
So the result of .

set theFunctions to {thisFunction(),thatFunction(),theOtherFunction()}

would be equal to.

set theFunctions to {"foobar",{1,2,3},1.2345}

assuming that your handlers’ definitions looked like this:

on thisFunction()
return "foobar"
end thisFunction

on thatFunction()
return {1,2,3}
end thatFunction

on theOtherFunction()
return 1.2345
end theOtherFunction

If you have a code like this

set theFunctions to {thisFunction(),thatFunction(),theOtherFunction()}

and then you say

set doFunction to item x of theFunctions

Applescript would just return the value of

item x of {"foobar",{1,2,3},1.2345}

If your handlers just return a value this might work. But if they contain real actions it will bring you in troubles!

In detail:

Your script (in the version you posted) runs the handler when the line

set theFunctions to {thisFunction(),thatFunction(),theOtherFunction()}

is run - not when the following line is run:

set doFunction to item x of theFunctions

the latter only returnes the values which the former line had set.

Hope this helps a bit to understand how Applescript handles handlers:rolleyes:

Vince

Yes , well it does explain why it doesn’t work. hmmmm

That is actually what I am trying to accomplish. A list of handlers. Or even a list of handler names.

how about:

on input(theString)
set thisList to {“this text”, “that text”, “the other text”}
tell application “Ircle” to set x to match theString with thisList
– the above part works. “match is in Ircle’s applescript dictionary” below is where I have problems
set theFunctions to {“thisFunction”,“thatFunction”,“theOtherFunction”}
set doFunction to item x of theFunctions
doFunction()
end input

on thisFunction()
–do some stuff
end thisFunction

on thatFunction()
–do some stuff
end thatFunction

on theOtherFunction()
–do some stuff
end theOtherFunction

Does that look like it would work? Can one call a function with a variable containg the name of the function as a string?

Well nope. That doesn’t work either. :frowning:

If I figure something out I’ll post it here for future readers.

This works - not exactly what you asked for, but a means of redirection:


repeat with k from 1 to 3
	myFuncs(k)
end repeat

on myFuncs(k)
	if k = 1 then
		funcA()
	else if k = 2 then
		funcB()
	else if k = 3 then
		funcC()
	end if
end myFuncs

on funcA()
	display dialog "A"
end funcA

on funcB()
	display dialog "B"
end funcB

on funcC()
	display dialog "C"
end funcC

It’s possible to do the sort of thing you say by treating the handler names as global variables, setting another global or property to the handler you want, and then “calling” that global or property:

global handlerList, thisHandler

on doThis()
	display dialog "Handler 'doThis()'"
end doThis

on doThat()
	display dialog "Handler 'doThat()'"
end doThat

on doTheOther()
	display dialog "Handler 'doTheOther()'"
end doTheOther


set handlerList to {doThis, doThat, doTheOther} -- NB. no parentheses
repeat with i from 1 to (count handlerList)
	set thisHandler to item i of handlerList
	thisHandler() -- NB. parentheses
end repeat

Obviously the handlers themselves all need to have the same number and type of parameters.

Another, more flexible way ” since it doesn’t rely on globals ” is to have the handlers in separate script objects and to put those script objects in the list:

on doItWithLocals()
	script doThis
		on thisHandler()
			display dialog "Script 'doThis'"
		end thisHandler
	end script
	
	script doThat
		on thisHandler()
			display dialog "Script 'doThat'"
		end thisHandler
	end script
	
	script doTheOther
		on thisHandler()
			display dialog "Script 'doTheOther'"
		end thisHandler
	end script
	
	set ScriptObjectList to {doThis, doThat, doTheOther}
	repeat with i from 1 to (count ScriptObjectList)
		tell item i of ScriptObjectList
			thisHandler()
		end tell
	end repeat
end doItWithLocals

doItWithLocals()

Nigel, the first one works for me without the globals. handlerList and thisHandler are only used in the (sorry, I don’t know my terminology) root ‘handler’ (on run). I am confused.

Launching subroutines by index:

set sub_routs to {a}
set hi to item 1 of sub_routs
hi(“hi”)
hi(“bye”)

on a(t)
display dialog t
return
end a

gl,

Thanx! That’s great! And so easy!

Hi, Qwerty.

Two things.

Firstly, it was quite late at night here when I posted the script. :slight_smile: In fact, only thisHandler (the variable used to “call” the handlers) needs to be a global or a property. The variable handlerList can be anything. Apologies for that.

Secondly, there’s a rather confusing situation regarding variables that are set in the ‘run’ handler. They’re “global” unless declared otherwise. I’ve put “global” in quotes here because you can’t access these variables from inside a handler unless they’re explicitly declared as global ” either at the top of the script, in the handler itself, or in both the handler and an explicit ‘run’ handler. However, they’re global in all other respects. Like properties, they “belong” to the script and can be referenced: ‘a reference to thisVariable’, ‘my thisVariable’. Their values also persist between runs of the script, though it’s awkward to make use of this and I’ve never seen the point of it. And they can be set to a handler in the script and used to call that handler.

Remember, it’s only the variables themselves that are global or local. The data they contain are just data - neither global nor local. So you could set a local variable to a handler, but you wouldn’t be able to use it to call the handler. However, you could then pass the handler on to a global and use that:

on fred()
	return 4
end fred

on bert(h) -- h is local to bert()
	global thisHandler

	set thisHandler to h
	thisHandler()
end bert

bert(fred)
--> 4

To avoid the use of globals, you could use properties of script objects instead:

on fred()
	return 4
end fred

on bert(h) -- h is local to bert()
	-- Create a script object o whose property thisHandler has the same value as h.
	-- o is a local variable, but the script it contains is just data.
	-- In the context of the data, thisHandler isn't a local but a property.
	script o
		property thisHandler : h
	end script

	o's thisHandler()
end bert

bert(fred)
--> 4

Fun, eh? :slight_smile:

Come to think of it, Nigel already wrote about how to place functions in lists. Sorry Nigel.

For a more indept look at the theory, read Nigel’s posts.

gl,

No problem, Kel. Your version’s very easy to read. :slight_smile: