Recursive error checking in a handler – how to get correct result?

I have a dialog in a handler which asks for user input, checks the input and redisplays if user left something out. Trouble is because it’s recursive, the wrong value for the important variable comes out. This code illustrates the issue:

set theLabel to "You need to supply a location."
set theFinalLocation to getLocation(theLabel)
on getLocation(theLabel)
	set theResult to (display dialog theLabel with title "Title" buttons {"Don't bother", "OK"} default answer "Location ?" default button 2)
	set theLocation to text returned of theResult
	if button returned of theResult is "OK" and (theLocation is "Location ?" or theLocation is "") then
		display dialog "You forgot to supply a location." buttons {"OK"}
		getLocation(theLabel)
	end if
	log theLocation
	set theResult to text returned of theResult
	return theResult
end getLocation
log theFinalLocation

If the user forgets to type the “location” they are reminded and the original dialog is redisplayed. After a few iterations the user gets it right. The processing of the iterations unwinds and if, say, there were three iterations theLocation ends up containing the original wrong value instead of the final correct value. That is unwinding of the script is in reverse order. So, the log might look like this:

 (*London*)
 (*Location ?*)
 (*Location ?*)
 (*Location ?*)

I’m sure there’s a principle I’m missing but I’m stuck and can’t find it. Is there a way to get the final, correct value for the theLocation variable ?

The issue is that the handler only sets ‘theLocation’ at the beginning of the handler and not when a valid location is actually entered.

If you want to stick with a recursive handler, then try adding an else to your if..then and set ‘theLocation’ there, like so:

set theLabel to "You need to supply a location."
set theFinalLocation to getLocation(theLabel)

on getLocation(theLabel)
	set theResult to (display dialog theLabel with title "Title" buttons {"Don't bother", "OK"} default answer "Location ?" default button 2 cancel button 1)
	set theLocation to text returned of theResult
	if button returned of theResult is "OK" and (theLocation is "Location ?" or theLocation is "") then
		display dialog "You forgot to supply a location." buttons {"OK"} default button 1
		getLocation(theLabel)
	else
		set theLocation to text returned of theResult
		return theLocation
	end if
end getLocation

Thanks. My code is a model of the actual. I can’t change the basic structure. But you’ve made me think of another idea which is to declare theLocation as global. For a reason I don’t understand, it always contains the value I need. So, my script is structured like this:

global theLocation
set theLocation to ""
set theLabel to "You need to supply a location."
getLocation(theLabel)
on getLocation(theLabel)
	set theResult to (display dialog theLabel with title "Title" buttons {"Don't bother", "OK"} default answer "Location ?" default button 2)
	set theLocation to text returned of theResult
	if button returned of theResult is "OK" and (theLocation is "Location ?" or theLocation is "") then
		display dialog "You forgot to supply a location." buttons {"OK"}
		getLocation(theLabel)
	end if
	set theResult to text returned of theResult
	return theResult
end getLocation
log theLocation```

Cheers.

Is there a particular reason for using recursion? The reason for your success is that you are setting a variable that is outside the recursive loop, but note that each time you recursively call a handler, its entire state is saved on the stack so that each call level has everything it needs - just leaving it would leak that memory.

You can always display the dialog in a repeat loop that doesn’t exit until the result is acceptable, then you don’t need to worry about unwinding or leaking the stack.