• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: *Very* strange script / global variable behavior
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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


  • Follow-Ups:
    • Re: *Very* strange script / global variable behavior
      • From: Doug McNutt <email@hidden>
    • Re: *Very* strange script / global variable behavior
      • From: Paul Berkowitz <email@hidden>
  • Prev by Date: Re: Scripting Energy Saver to Sleep Display Now?
  • Next by Date: Re: Scripting Energy Saver to Sleep Display Now?
  • Previous by thread: Re: *Very* strange script / global variable behavior
  • Next by thread: Re: *Very* strange script / global variable behavior
  • Index(es):
    • Date
    • Thread