Re: Question about submodules
Re: Question about submodules
- Subject: Re: Question about submodules
- From: email@hidden
- Date: Fri, 10 Nov 2000 16:06:46 -0500
On Thu, 9 Nov 2000 16:19:07 -0600, Bill Planey <email@hidden> asked,
Can Submodule_A (as part of Script_1) load Submodule_B
if Script_1 also loads Submodule_B? In other words, can the
same submodule serve both the script and its subscript?
Yes. You will have two separate objects, though, with different names. For
example,
--- Submodule B ---
-- implements a colored thing.
property color : "Red"
to radiate()
return "I'm " & color
end
to recolor into newColor
set color to newColor
end
--- Submodule A ---
-- implements a colored thing that remembers its previous color
property colorizer : load script alias "Disk:Folder:Submodule B"
property previousColor : missing value
on radiate()
if previousColor is missing value then
return radiate() of colorizer
else
return radiate() of colorizer& ", but I used to be " & previousColor
end if
end radiate
to recolor into newColor
set previousColor to color of colorizer
tell colorizer to recolor into newColor
end
---- Script 1 ---
property memoryColorizer : load script alias "Disk:Folder:SubmoduleA"
property noMemoryColorizer : load script alias "Disk:Folder:SubmoduleB"
tell memoryColorizer to recolor into "Aqua"
tell noMemoryColorizer to recolor into "Sage"
{radiate() of memoryColorizer, radiate() of noMemoryColorizer}
--> result: {"I'm Aqua, but I used to be Red", "I'm Sage"}
You'll notice that you have two separate copies of Submodule B, each with its
own separate value for the 'color' property. One instance of the submodule is
referred to as 'noMemoryColorizer', and the other is 'colorizer of
MemoryColorizer'
If you really were worried about the wasted space of keeping two copies, and
didn't care that they would share data (or if there were no data, like in a
function library), you can only load once, and then use a "set" or property
declaration to create an easier name for the second instance of Submodule B.
But this has the downside of making the design of Script 1 dependent of the
details of Submodule A. If you later change Submodule A so it doesn't use
Submodule B, you will have to fix Script 1. With that warning, you can say,
---- Script 1a ---
property memoryColorizer : load script alias "Disk:Folder:SubmoduleA"
property noMemoryColorizer : colorizer of memoryColorizer
tell memoryColorizer to recolor into "Aqua"
tell noMemoryColorizer to recolor into "Sage"
{radiate() of memoryColorizer, radiate() of noMemoryColorizer}
--> result: {"I'm Sage, but I used to be Red", "I'm Sage"}
Notice that calling Submodule B as part of noMemoryColorizer changed the color
of both objects, and did so "behind the back" of the memoryColorizer, breaking
its memory function.
If you want to not share data, but don't want duplicate copies of the handlers,
you can copy the script object.
---- Script 1a ---
property memoryColorizer : load script alias "Disk:Folder:SubmoduleA"
copy colorizer of memoryColorizer to noMemoryColorizer
tell memoryColorizer to recolor into "Aqua"
tell noMemoryColorizer to recolor into "Sage"
{radiate() of memoryColorizer, radiate() of noMemoryColorizer}
--> result: {"I'm Aqua, but I used to be Red", "I'm Sage"}
(AppleScript is smart enough not to copy the whole text of the handlers when it
makes a copy of a script object. I suppose it copies pointers instead. If you
measure memory use, when you make a million copies of a script object that
contains a very long handler, you consume just a few million bytes, and not (a
million) x (very long) bytes. )
If you are just using function libraries, don't worry. You are wasting more
space loading handlers you never use from a large library than you'll reclaim by
not loading one handler twice. If your scripts become too large, split the
libraries up. Or, create copies that are saved "run only" and load those.
(Don't forget to keep editable originals that aren't run-only!)
If you have a huge function library, only need one handler, and are worried
about space, you can load just the handler. Assuming the library "Numeric
Functions" includes a maximum-finding function you want. Load just that
function like this:
property max : maximum of (load script alias "Disk:Folder:Numeric Functions")
max({3,4,7,5,2})
--> result: 7
In this example, "maximum" is the name of the handler in the library, and "max"
is the name I've given it in this script. Because the value of the property is
calculated at compile time, this is very efficient, and allows you to distribute
the script without having to distribute the library. (Although without the
library, you can't re-compile the script.) This approach also makes for
easy-reading scripts, since you say "max({1,2,3})" and not "maximum({1,2,3}) of
NumberFunctions" which you'd have to do if you loaded the entire script library.
If you want more than one, but not all, of the handlers, it gets less easy. You
can brute-force it, calling "load script" each time. You can use a list or
record to get the handlers you need, but you'll have to then separate them out
into their own properties, like this
property functions : {max: maximum, min: minimum} ,
of (load script alias "Disk:Folder:Numeric Functions")
property max : max of functions
property min : min of functions
max({3,4,7,5,2})
--> result: 7
You can't just load 'functions' and then call handlers that are elements of the
record, like "max({3,2,4}) of functions" because you'll get an error,
"{max:<<handler>>, min:<<handler>>} doesn't understand the max message."
Records can't invoke handlers. They have to be in properties or global
variables to be called.
Thanks to Richard 23 for his insights on how to store and copy handlers
dynamically and still be able to call them.
--
Scott Norton Phone: +1-703-299-1656
DTI Associates, Inc. Fax: +1-703-706-0476
2920 South Glebe Road Internet: email@hidden
Arlington, VA 22206-2768 or email@hidden