Need help understanding a script error about an undefined variable

For a service script, I am trying to fetch some “origin” information from any frontmost application.

For instance, for Browsers, I want to fetch the current URL, from apps with document windows I try to get the doc or window name.

Now it happens sometimes, e.g. when I run it on Safari while it’s entered a search string that has not been turned into a URL yet, that the script aborts with the error: The variable res is not defined. But hte variable is defined, I clearly always use “set res …” before I access it, right?

Can someone tell me what I’m doing wrong?

Also, maybe “null” is not the best way to indicate that there’s no value returned. What’s better? Would it work better if I replaced all “null” occurances with “missing value”?

Bonus question: The script refers to “Google Chrome”. Now, if a user does not have Chrome installed, the script won’t run, right? Is there a way to make the script compilable regardless?

on infoForAppWithID(appID)
	if appID is "com.apple.Finder" then
		-- No need to get either file or URL from the Finder as we already should have them in the clipping.
		return null
	end if
	set res to getURLFromAppWithID(appID)
	if res is not null then
		return res
	end if
	set res to itemForCurrentSelectionInAppWithID(appID)
	return res
end infoForAppWithID

on getURLFromAppWithID(appID)
	if appID = "com.apple.Safari" then
		try
			tell front window of application "Safari"
				return URL of current tab
			end tell
		end try
	else if appID = "com.google.Chrome" then
		try
			tell front window of application "Google Chrome"
				return URL of active tab
			end tell
		end try
	end if
	return null
end getURLFromAppWithID

on itemForCurrentSelectionInAppWithID(appIdentifier)
	try
		tell application id appIdentifier
			try
				set d to first document
			on error
				try
					set d to first document of first window
				end try
			end try
			set x to path of d
			return x as POSIX file
		end tell
	end try
	return null
end itemForCurrentSelectionInAppWithID

If I understand well, your code calls the handler infoForAppWithID(appID)
then it calls the handler getURLFromAppWithID(appID).

Assuming that I am right, you define a variable named res in the handler infoForAppWithID(appID)
but there is no reason for the calling code to see this variable.

my myHandler()
log result (*beurk*)
try
	log res
on error errMsg
	log errMsg (*La variable res n'est pas définie.*)
end try

set res to myHandler()
log res (*beurk*)

set res to myAltHandler()
log res (*beurkAlt*)

on myHandler()
	set res to "beurk"
	return res
end myHandler


on myAltHandler()
	set altRes to "beurkAlt"
	return altRes
end myAltHandler

Yvan KOENIG running El Capitan 10.11.4 in French (VALLAURIS, France) samedi 14 mai 2016 19:56:48

I do not access “res” anywhere outside of infoForAppWithID(), so your explanation does not fit, I think.

The issue has to do with the fact that Safari does not give an URL. It rather gives an error, which is caught by the try clause, and then the function should exit with “return null”. That should then lead to itemForCurrentSelectionInAppWithID being call, which should also fail and return null, It’d expect.

The calling code looks like this:

set appInfo to infoForAppWithID(appID)
if appInfo is not null then
	tell current clipping
		if class of appInfo is «class furl» then
			-- It's a file -> Set the clip's file reference
			set file reference of first clip item to appInfo
		else if name is "" then
			-- Set the name of the clipping
			set name to appInfo as rich text
		else
			-- Set the "info" property. That'll appear in the preview window.
			set info to (appInfo as rich text) & return & info
		end if
	end tell
end if

You will have to double check your code.

I added several log instructionsto trace the script

set appID to "com.apple.Safari"
set appInfo to infoForAppWithID(appID)
(*
# Disabled because current clipping doesn't compile here !
if appInfo is not null then
   tell current clipping
       if class of appInfo is «class furl» then
           -- It's a file -> Set the clip's file reference
           set file reference of first clip item to appInfo
       else if name is "" then
           -- Set the name of the clipping
           set name to appInfo as rich text
       else
           -- Set the "info" property. That'll appear in the preview window.
           set info to (appInfo as rich text) & return & info
       end if
   end tell
end if
*)
on infoForAppWithID(appID)
	log "infoForAppWithID(appID)"
	log appID
	if appID is "com.apple.Finder" then
		-- No need to get either file or URL from the Finder as we already should have them in the clipping.
		return null
	end if
	log "here I am"
	set res to getURLFromAppWithID(appID)
	log res
	if res is not null then
		return res
	end if
	log res
	set res to itemForCurrentSelectionInAppWithID(appID)
	return res
end infoForAppWithID

on getURLFromAppWithID(appID)
	log "getURLFromAppWithID(appID)"
	log appID
	if appID = "com.apple.Safari" then
		try
			tell front window of application "Safari"
				set theURL to URL of current tab
				log theURL
				return theURL
			end tell
		end try
	else if appID = "com.google.Chrome" then
		try
			using terms from application "Google Chrome"
				tell front window of application id appID
					-- return URL of active tab
					return «class URL » of «class acTa» # the reserved words are replaced by their raw code (the chevrons one)
				end tell
			end using terms from
		end try
	end if
	return null
end getURLFromAppWithID

on itemForCurrentSelectionInAppWithID(appIdentifier)
	log " itemForCurrentSelectionInAppWithID(appIdentifier)"
	log appidetifier
	try
		tell application id appIdentifier
			try
				set d to first document
			on error
				try
					set d to first document of first window
				end try
			end try
			set x to path of d
			return x as POSIX file
		end tell
	end try
	return null
end itemForCurrentSelectionInAppWithID

When I run the script above, I get :

(infoForAppWithID(appID))
(com.apple.Safari)
(here I am)
(getURLFromAppWithID(appID))
(com.apple.Safari)
tell application “Safari”
get URL of current tab of window 1
(http://macscripter.net/post.php?tid=44891)
end tell
(http://macscripter.net/post.php?tid=44891)

When I replace the first instruction by :

I get :

(infoForAppWithID(appID))
(com.google.Chrome)
(here I am)
(getURLFromAppWithID(appID))
(com.google.Chrome)
tell application “Google Chrome”
get URL of active tab of window 1
→ “https://fr.search.yahoo.com/?fr=spigot-yhp-gcmac&ilc=12&type=453483
end tell
(https://fr.search.yahoo.com/?fr=spigot-yhp-gcmac&ilc=12&type=453483)

I am unable to reproduce what you describe.
I hope that you see the way to get the code to compile when Chrome is unavailable.

Yvan KOENIG running El Capitan 10.11.4 in French (VALLAURIS, France) samedi 14 mai 2016 21:19:47

Solely based on your statement I quoted: It seems that one of the commands sets an undefined variable. This should be considered a bug and should be reported to the developers. Some commands always returns an undefined variables but properties should always contain a value and commands either always return an undefined value or never.

The most easiest way to check if an variable is undefined is using an exception:

set res to beep 0

try
	res
on error msg
	-- oops something went wrong
	display alert "Undefined variable" message msg
	return
end try

Ah, so you mean that it’s not the Applescript engine but the app that I asked to get a value from. That would make more sense.

So, I just learned that there is another state that I’ve not seen before, it seems: <> (or what AS called “undefined”).

So far I only knew of “missing value”. But if I do this for a Safari window with no open URL:

tell application id "com.apple.Safari" -- Safari.app
	URL of tab 1 of window 1
end tell

Then the result is non-existing. Script Debugger shows <> for it. I guess that’s what is then triggering the error, as it seems that Applescript does not let me compare an empty value to something else.

Using try seems to be the only way to even test that state. Not even the “exists” command works.

Anyway - thanks, you answer helped me fix my code, and now it runs without a hitch.