Re: *Very* strange script / global variable behavior
Re: *Very* strange script / global variable behavior
- Subject: Re: *Very* strange script / global variable behavior
- From: Axel Luttgens <email@hidden>
- Date: Sun, 13 Mar 2005 17:01:23 +0100
Neil Faiman wrote:
I've been poring over Matt Neuberg's invaluable Definitive Guide, and
I thought I pretty much grasped the rules about the interactions of
scripts, handlers, variable scope, etc. Then I encountered this thing.
(I discovered this in a much bigger AppleScript Studio project, and
simplified it to this little reproducer, which demonstrates the
problem in Script Editor.)
[...]
While reading Neil's result, I was first baffled.
And the resulting thread left me somewhat unsatisfied: generally, when
such behaviors are encountered in AppleScript, an explanation may be found.
But all I could read were references to "obscure bugs".
As a reminder, Neil's problem may be simplified as follows.
Let's first look at this seemingly innocuous piece of code:
-- Code1
property SomeProp : "abc"
script LogIt
log SomeProp
end script
set SomeProp to "xyz"
tell LogIt to run
--> (*xyz*)
Seems to be "logical", doesn't it?
OK; here then a slight variation introducing "Neil's effect":
-- Code2
property SomeProp : "abc"
script LogIt
log SomeProp
end script
set x to me
set SomeProp to "xyz"
tell LogIt to run
--> (*abc*)
Damn!
(I mean, I was baffled ;-) ).
Various posts in the thread suggested that Code2 needed to be correctly
rewritten.
I think so too, but perhaps not for the same reasons as the ones that
were invoked.
In fact, I believe the problem (if any) is already present with Code1.
Code1 is plenty of OO-terminology, but doesn't make use of any
OO-features at all.
Telling script LogIt to run doesn't allow to reach some property of the
top-level script: it's just a matter of lexical scoping:
-- Code3
script LogIt
log SomeProp
end script
property SomeProp : "abc"
set SomeProp to "xyz"
tell LogIt to run
--> Error: variable SomeProp is undefined
So, in Code1, some value could be reached from within script LogIt
because a property declaration for identifier "SomeProp" appeared before
in the code's TEXT, at the same or at an outer level of identation.
Nothing to do with inheritance. [1]
By contrast, should someone have asked why following code errors,
everybody would have said "hey! that's normal! you wouldn't want to be
able to clash local variables that way, would you?":
-- Code4
set SomeProp to "xyz"
script LogIt
log SomeProp
end script
tell LogIt to run
--> Error: variable SomeProp is undefined
So, everyone would understand the error produced by Code4 because of
basic and almost universal programming rules.
The same way, one tends to consider normal that Code1 "works", because
of its apparent OO-contents; but Code1 just "works" because of lexical
rules.
In fact, a closer look at Code1 would lead to the conclusion that it
just doesn't mean anything, according to usual scoping rules encountered
in other languages; unless one is aware of the rule allowing such a code.
The lexical scoping allowing Code1 to "work" is very particular to
AppleScript. [2]
I suspect this rule to have been introduced so that one may quickly
write a piece of code such as:
-- Code5
property AProp : "abc"
set AVar to "def"
log AProp & AVar & name
--> (*abcdefScript Editor*)
It allows to hide the fact that Code5 itself IS a script object and to
transparently mix variables and properties (for the good or the bad).
Nice for quick and small projects, as well as for casual AppleScripters
who have to easily code repetitive tasks: no need for big theory.
But Code1 (assuming it is representative of a real big project) is not a
quick amateur program anymore.
It explicitely uses OO-concepts, and as such should be more explicit.
The LogIt script is clearly intended to access its parent's property; so
let's explicitely use inheritance instead of relying on ambiguous
scoping: [3]
-- Code6
property SomeProp : "abc"
script LogIt
log my SomeProp
end script
set SomeProp to "xyz"
tell LogIt to run
--> (*xyz*)
This has various consequences.
First, Code6 should appear more sensible than Code1 to someone not
accustomed to AppleScript.
Second, a script's property now clearly is a... script property, and not
a strange position-dependent thing; in contrast to Code4:
-- Code7
script LogIt
log my SomeProp
end script
property SomeProp : "abc"
set SomeProp to "xyz"
tell LogIt to run
--> (*xyz*)
Third, it hinders "Neil's effect" to occur:
-- Code8
property SomeProp : "abc"
script LogIt
log my SomeProp
end script
set x to me
set SomeProp to "xyz"
tell LogIt to run
--> (*xyz*)
Lots of unsuspected behaviors occur in AppleScript because of that handy
(?) lexical scoping rule, that allows to write complex code and shoot in
the foot at the same time.
Other such rules, but dynamic ones:
In the search of a global G, if there is no such one, but if a property
G may be reached, that property is used instead.
In the search of a property P, if there is no such one, but if an
INITIALIZED global P may be reached, that global is used instead.
In fact, these rules too allow to write quick code such as Code5.
It could perhaps be a good idea to have a flag in the compiler that gets
raised as soon as some keywords ("script", "property", "global"...)
appear in the code, turning those permissive rules off.
But, in the absence of such a flag, it seems it is assumed that the
applescripter writing Code1 should be aware of the semantical
consequences of, say, the lack of a tiny keyword such as "my"...
So, yes, Code2 produces a very surprising result.
But it should be recognized that this is mainly because it contains a
basic programming flaw.
AppleScript's "handy" behaviors are then just adding their own layer of
confusion.
To be followed...
Axel
[1] Note that a similar scoping rule holds for globals too:
-- Code1bis
global SomeGlob
script LogIt
log SomeGlob
end script
set SomeGlob to "xyz"
tell LogIt to run
--> (*xyz*)
-- Code3bis
script LogIt
log SomeGlob
end script
global SomeGlob
set SomeGlob to "xyz"
tell LogIt to run
--> Error: variable SomeProp is undefined
[2] And is -more or less accurately- defined in the ASLG, thus having
the status of being part of the language specification.
[3] To completely bypass the lexical rule, one should write:
-- Code6bis
property SomeProp : "abc"
script LogIt
log my SomeProp
end script
set my SomeProp to "xyz"
tell my LogIt to run
--> (*xyz*)
But this would perhaps quickly become very pedantic...
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Applescript-users mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden