How to encapsulate and reach to an external handler

Hi reader,

The following AppleScript does not work. When run in “Script Debugger”, it fails at the call to “addtwonumbers(x,y)” claiming that this entity is not understood - i.e., it can’t be located/accessed.
Commenting out the line “property parent : AppleScript” allows it to work as expected.

The question is -
if I use “property parent : AppleScript”
how can I get the encapsulated handlers get to external handlers

The reason I want to use the the “property parent : AppleScript” is that if I do not - “LNS Script Debugger” states that there is an “internal table overflow”, throws an error and will not allow me to debug the script in debug mode (the internal table overflow message does not occur when debug mode is switched off). The script itself is not that big - a hundred lines or so. The problem causing the internal table overflow error appears to be the result of several objects being defined and initialized.

Anyway - any suggestions how one might solve this problem would be much appreciated.


use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

on addtwonumbers(a as integer, b as integer)
	return (a + b)
end addtwonumbers

on encapsScript()
	script abc
		property parent : AppleScript
		property c : 0 as integer
		
		on testThis(x as integer, y as integer)
			set c to addtwonumbers(x, y)
			return (c)
		end testThis
	end script -- abc
end encapsScript

local d

set es to encapsScript()
tell es
	set d to testThis(1, 2)
end tell
d

Two suggestions:

  • Don’t try to solve the problem by using a parent property like that. It’s not the answer (as you have already found out).

  • Don’t try to treat AS handlers as objects; they’re not, and even though they sometimes appear to behave as such, it is at best undefined bahavior. If you want an object, use a script object:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

on addtwonumbers(a as integer, b as integer)
	return (a + b)
end addtwonumbers

	script abc
		property c : 0 as integer
		
		on testThis(x as integer, y as integer)
			set c to addtwonumbers(x, y)
			return (c)
		end testThis
	end script -- abc

local d

tell abc
	set d to testThis(1, 2)
end tell
d

Hi Shane and other interested readers,

Thanks for the suggestions - intriguing! When I read AppleScript language references several suggested that by wrapping a “script” in a AS handler I could use the construct to create instances of a scrip object. This became useful because I could then do something like in the code snippet below (which is using the construct like it was an object).

The result is effectively two objects that have different local storage states.

As you point out - this construct and usage creates problems that can be masked by using a parent property - but that has side effects as well. So better to avoid this method.

Is there a syntax that allows me to do what I want a script object (creating separate instances) without using an AS handler?
If not I will have to rethink how I use AppleScript.


use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

on addtwonumbers(a as integer, b as integer)
   return (a + b)
end addtwonumbers

on encapsScript()
   script abc
       property parent : AppleScript
       property c : 0 as integer
       
       on testThis(x as integer, y as integer)
           set c to addtwonumbers(x, y)
           return (c)
       end testThis
   end script -- abc
end encapsScript

local d

set es1 to encapsScript()
tell es1
   set d to testThis(1, 2)
end tell

set es2 to encapsScript()
tell es2 
  set e to testThis(4, 5)
end tell 

Hi. Perhaps I don’t understand the question or goal, as I’m not really sure why an object is needed to have something be local. Things defined within a handler are local instances, unless explicitly made global; my example violates the handler’s stated purpose of simply adding two numbers, but it demonstrates this point.


set c to 20
display dialog addTwoNumbers(1, 2)  -->10, since local c was added to last handler operation
display dialog c  -->20, since global c

#global c --if enabled, c will be set by the handler; in this case  -->7



on addTwoNumbers(a, b)
	set c to 7
	(a + b) + c
end addTwoNumbers

Your original code without the parent property is doing what you want. The handler is returning its last result, which is a script object. If you’re getting internal table overflows, you need to try to work out why that’s happening.

Having said that, my personal opinion is that although AppleScript is in theory an OOP language in this sense, using it as such is often unnecessary, and sometimes problematic.

There is another method like this:


script anClass
	property anValue : missing value
	
	on setValue(val)
		set my anValue to val
	end setValue
	
	on getValue()
		return my anValue
	end getValue
end script

copy anClass to instance1
copy anClass to instance2

instance1's setValue(1)
instance2's setValue(2)

return {instance1's getValue(), instance2's getValue()}

Basically the handler method and using copy are doing the same, they create an instance by copying an script object. There is however one major difference and that that the handler method is dynamic while the copy method is static. For example with the handler method you can send an parent property while that is not possible using copy.


on createInstance(_parent)
	script -- anonymous
		property parent : _parent
		
	end script
end createInstance

on add(a, b)
	return a + b
end add


set o to createInstance(me)
o's add(4, 5) -- Result: 9
set o to createInstance(AppleScript)
o's add(4, 5) -- Result: error

Last time I gave not entirely correct information, so I deleted the post. Although my main point was correct: setting the parent property of the abc script to AppleScript or to me is not possible at compile time (explicitly). Because the compiler is smart and sees a violation of the OOP concept in this.

The fact is that in this case the abc script inherits all properties and all handlers of the head script, including the handler in which it is encapsulated. It is like a snake swallowing its tail.

But setting the parent property of the abc script to AppleScript or to me is possible at runtime.

The exact answer to the OP’s question is in the following script. I specially added additional handlers of 2 levels to it: 1) belonging to the head script and 2) belonging to scripts b and c. Tested:


use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
property parent : AppleScript -- or, me -- I made it explicit to understand better

on addtwonumbers(a as integer, b as integer)
	return (a + b * b)
end addtwonumbers

script b
	property c : 0
	on addtwonumbers(a as integer, b as integer)
		return (a + b)
	end addtwonumbers
end script

script c
	property c : 0
	on addtwonumbers(a as integer, b as integer)
		return (a + a + b)
	end addtwonumbers
end script

on encapsScript(_parent)
	script abc
		property parent : _parent -- its own parent property
		property d : 500
	end script -- abc
end encapsScript

set es1 to encapsScript(b) -- set its own parent property to «script b»
tell es1 to addtwonumbers(1, 2) -- result:3

set es1 to encapsScript(c) -- set its own parent property to «script c»
tell es1 to addtwonumbers(1, 2) -- result:4

set es1 to encapsScript(me) -- set its own parent property to header script
tell es1 to addtwonumbers(1, 2) -- result:5