Frontier website on www.scripting.com
How Scoping Works
A lesson in variable name scoping from a longtime Frontier user.
By Scott Lawton, http://www.tiac.net/prefab/Although I've been using Frontier for quite awhile, I just got bit by something that's likely to happen to others. It took me a long time to track down, so I thought I'd share the lesson to perhaps save someone else the trouble.
In Frontier's UserTalk and any other block-structured language, all variables have a "scope", i.e. a context in which they are valid. Although UserTalk doesn't require that you declare variables (using "local"), experienced scripters highly recommend it.
local « declare x as a variable xTraditional computer languages such as Pascal and C require that variables be declared with a certain datatype, e.g. string, number or whatever. Frontier lets you change the datatype on the fly, just by assigning a new value. (A very handy feature!) You can also assign an initial value in the "local" block, and define many variables in a single block. (In fact, you don't have to use the block structure for local, though I prefer it.)
local « declare x & y and give them initial values x = 1 y = "hello"In general, the scope of a variable is the "block" (level of outline) in which the "local" definition appears (or the first use, if you don't declare it), plus all deeper levels.
A made-up example:
local x = 10 msg (x) msg (y) «error: y hasn't been declared or defined if x > 5 local y = 5 msg (x) «x is still valid here msg (y) «y's "scope" is this "if" blockNote that you can use the same name for two different values, if you declare the variable again at a lower level. However, this approach can lead to confusion and is not recommended.
local x = 10 msg(x) « 10 if x > 5 local x = "hello" « a new variable that's also called "x" y = 5 msg(x) « hello ... NOT 10 msg(y) « y's "scope" is this "if" block msg(x) « 10 ... NOT hello (note the outline level)Again, it's confusing to have the letter x stand for two different variables ith different scope, so it's generally not a good idea. Why make scripting harder than it has to be?
By the way, one of the coolest things about Frontier is that the block structure is tangible since it's reflected in the outline (i.e. the indentation).
Of course, the Object Database is central to Frontier. But, be careful. Some locations are "global" to all of your scripts. If you accidently use a name that happens to correspond to a global variable, and you didn't declare yours as a local, you could change the value of something that really shouldn't be changed.
Let's say you liked to use short variable names. Maybe you needed a flag to tell you whether or not you created an outline.
cr = false «assume it hasn't been createdWait! If you run this script, you've just reassigned system.verbs.constants.cr from "\\r" (carriage return) to false. That's likely to break lots of scripts, and maybe confuse you when you eventually discover the error and have long since forgotten about your abbreviated "create" flag.
Two lessons:
1. declare variables
local «this is fine, it won't overwrite the global cr = false «assume it hasn't been created2. use longer variable names, e.g. created or createdFlag
Sometimes you want to use variables from the object database that aren't in a global location, e.g. FileMaker.id. In the old days (Frontier 1), you always had to type out the full Object DB path. Fr. 2 (I think) added the "with" keyword.
The following two are equivalent. msg (FileMaker.id)
with FileMaker msg (id)
Here's where it gets tricky. What if you have some globals, some locals, and some variables in a table referenced by "with"? Which wins? Well, I lost lots of time by not paying attention to this question.
local ID with myApplication ID = create(s) doSomething(ID) dispose(ID)Do you spot the mistake? I remembered to declare the local, but I declared it the wrong place, i.e. one level too high. Frontier (apparently) looks first in locals declared inside the "with" block, that at the tables referenced by "with", then walks up the hierarchy for other locals, then (I think) the globals.
So, although I didn't realize it, my local "ID" was left alone, and I essentially ran:
myApplication.ID = create(s) « OOPS, not what I meantSince my "glue" scripts depended on myApplication.id being the correct string4 creator code (not the values passed back by create), the rest of my script broke.
Here's a sample glue script:
on doSomething(someValue) with myApplication return appleEvent (id, 'xxxx', 'yyyy', '----', someValue)So, Frontier was trying to send the AppleEvent to a sort of random place since the ID was wrong.
Happy scripting; I hope my comments are helpful.
![]()
© Copyright 1996-97 UserLand Software. This page was last built on Wed, Jan 22, 1997 at 3:08:18 PM with Frontier. Thanks for checking it out! Dave