Re: Scripter (The Program)
Re: Scripter (The Program)
- Subject: Re: Scripter (The Program)
- From: email@hidden
- Date: Fri, 10 Nov 2000 14:34:56 -0500
[ Warning: This thread has wandered off into obtuse language issues,
of interest only to propeller-head programmers, and not relevant to
most scripters. If you use AppleScript to automate your workflow,
make your newspaper publish itself, or set up your school's computer
lab, ignore this thread. But if you think Church numerals reveal the
higher truths of the universe, put on your pocket protector and jump in.
There. That should keep the Wrath of Cal off our heads. ;-) ]
On Thu, 09 Nov 2000 07:25:19 -0500, From: Bill Cheeseman <email@hidden>
responded,
>
> Ok. Since several people are extolling the virtues of Scripter perhaps
>
> someone who has the latest version could test something for me. I'd
>
> like to know if the following legal techniques which work in every other
>
> script editor still fail to compile in Scripter....
>
>
I'm happy to respond to your challenge. Some of your tests are illegal, and
>
Scripter is correct to catch your syntax error. One of Scripter's advantages
>
is that it employs stricter syntax checking than other products, and it is
>
showing its strength compared to other script editors in this regard by
>
refusing to compile some of your tests. You were misled by the fact that
>
Script Editor (and other script editors, I gather) incorrectly overlooked
>
your syntax error.
[ The entire interplay of examples and counterexamples deleted. ]
I had discussed how AppleScript handles functions with Richard 23 on the
MACSCRPT list, and he showed me that handlers were essentially full-fledged
values, assignable and able to be passed as arguments, just like any other
class.
Handler variables are initially assigned their values at compile time from their
declaration. Just as "property N : 0" creates a variable N and assigns it a
value of 0, "to foo() ... end foo" creates a variable 'foo' and assigns it a
value of the handler.
Handlers can be assigned to variables, and handlers can be redefined by that
assignment. So,
to foo()
"Foo"
end foo
to bar(x)
"Bar " & x
end bar
set foo to bar
foo("Hi")
--> result: "Bar Hi"
The only constraint on the use of a handler as a full-fledged type class is that
to invoke the function with its arguments, you need to ensure the variable
containing the handler has more than local scope. (It doesn't have to be global
scope; you can assign a handler to a variable of a script object; in that case
the handler has the script object as its scope, and doesn't have global scope.)
In the example above, "foo" can have a new handler assigned and successfully
called because it was originally a handler defined at the top level of the
script and so had global scope. Instead of the definition of foo() as a
handler, we could have had "property foo : 0" or "global foo". But if foo
weren't declared global, the assignment "set foo to bar" would have created a
local variable foo, and local variables are not part of the search chain for
finding handlers.
This is a significant issue if you want to pass a handler as an argument to a
function. (This is a handy thing to do, both to implement 'callbacks' in
modular software, and for any time when you want to parameterize a function, but
don't want the complexity of a script object. Say you have a generic sorting
routine, and need to sort words by their third letter. Write a function that
does such a comparison, and make it a parameter of the 'sort' handler. )
Here's an example of a handler that applies some handler to every item of a
list. It returns a list of the results of each application.
to apply(func, args)
global callableFunc -- need large enough scope to make a handler callable
set callableFunc to func
set resultList to {}
repeat with eachItem in args
set end of resultList to callableFunc(eachItem)
end repeat
return resultList
end apply
to double(x)
x & x
end
apply(double, {1,2,3})
--> result: {{1,1}, {2,2}, {3,3}}
If we didn't have the 'global callableFunc' statement, and just tried to use in
the central loop, the call, 'set end of resultList to callableFunc(eachItem)',
we'd get the error "<<script>> doesn't understand the func message." Within the
function body, the formal parameter func acts like a local variable.
Bill Cheeseman points out that Scripter does compile-time argument checking for
function calls.
>
I recommend that you upgrade. Scripter's more-stringent syntax checking
>
helps to overcome misunderstandings like this.
Personally, I'm all in favor of strongly-typed, "bondage-and-discipline"
programming languages like Ada, Pascal, and Java. Catch as many errors at
compile time as possible. And I get very nervous when I see Richard 23's
"compile on the fly" approach to redefining handlers or coercing values. These
methods, and redefining handlers on-the-fly, are a fast route to unreadable
scripts. And unreadable scripts have no future.
But AppleScript isn't a strongly-typed language. It is dynamically typed. Like
the AppleScript Language Guide says at the beginning of the Overview,
"AppleScript is a dynamic, object-oriented script language." It doesn't enforce
a requirement that calling parameters must match declaration parameters if you
are calling application handlers or calling handlers in script applications, and
it doesn't enforce it within the script except at run time.
Existentially, what is the "real" AppleScript? Is it the language that the
Script Editor implements, or is it the language the AppleScript Language Guide
defines? Neither is definitive. The Script Editor has bugs, which I don't
think should be part of the true language, and the ASLG is incomplete and has
errors as well. But if you say that its a dynamic language, then you expect it
to act like the other dynamic languages such as LISP, Smalltalk, or
Objectionable-C.
It seems Scripter helps the user by noticing discrepancies between the declared
arguments and the called arguments, which usually is a problem, but can be legal
if the hander's meaning is redefined on the fly. If I were Main Event, I'd
certainly warn the user if the arguments didn't match. It either going to be a
run time error, or its a poor design. (AppleScript doesn't have a varArgs
mechanism, and no way for the handler to count its arguments or to create
dynamically handlers with different numbers of arguments [short of
compile-on-the-fly]. So a handler that gets redefined from, say, one argument
to two is really two different, incompatible handlers sharing the same name.
The program would be equally readable if they just had different names.) But I
don't think it can be called illegal syntax at compile time.
And when I need callbacks or need to use a handler as a parameter, I generally
wrap the data and the hander in a script object. I can then call the script
object, or pass the script object as the parameter. For example, if I wanted to
sort in custom order, instead of providing a list of words and a handler to sort
them, I provide a list of word-objects, and each word-object had a handler to
compare itself to another word-object. I recently wrote a very simple XML
renderer. The usual way to do this in C is with callbacks, but I instead wrote
script objects for each type of element, each with a "parse" and a "render"
handler.
--
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