local and do <commands> - what NOT to do

Mark Waddingham mark at livecode.com
Thu Feb 18 06:52:15 EST 2016


On 2016-02-18 09:03, Kay C Lan wrote:
> The Dictionary entry for 'local' has this Example:
> 
> -- To make a numbered list of variables:
> repeat with x=1 to 20
>   do "local tVar_" & x & "; put empty into tVar_" & x
> end repeat

Okay so this kind of code pattern originates from HyperCard which did 
not have arrays. If you wanted to manipulate multiple separate values 
without restriction on their contents (e.g. elements of a list which 
need to contain the delimiter) then it was probably one of the only 
options.

An important thing to remember about LiveCode compared to HyperCard (as 
far as I understand, at least) is that LiveCode *compiles* scripts ahead 
of time; in contrast to HyperCard which operated on a line-by-line 
execution basis. Strict Compilation Mode is a compilation option - it 
has no effect at execution time.

If Strict Compilation Mode is turned off, then when a script is compiled 
any token which is where a variable could be is treated as an 'unquoted 
literal'. Such unquoted literals are implemented by the engine by 
declaring a variable whose contents is the name of the variable but only 
up until appoint the variable is assigned a value - at which point it is 
cleared before hand. e.g.

   put foobar into tVar
   put barfoo after foobar
   put foobar

Will result in:
   - tVar containing foobar
   - foobar containing barfoo

So, with that in mind let's take a look at what is happening in the 
above code snippet:

   repeat with x=1 to 20
     do "local tVar_" & x
     do "put x*x into tVar_" & x
   end repeat
   put tVar_5 into msg  --not hidden in <do>

With Strict Compilation Mode turned off, this script will compile fine - 
it will cause the handler which the code is placed in to have an 
'unquoted literal variable' tVar_5 defined - at the point of 
compilation. This means that when you run the script, you get a 'local 
variable shadows another' parsing error when you do 'do "local tVar_5"' 
as there is already a variable that exists with that name. Indeed, if 
you try this (again with Strict Compilation Mode turned off):

   repeat with x=1 to 20
     do "local tVar_" & x
     do "put x*x into tVar_" & x
   end repeat
   put tVar_5 into msg  --not hidden in <do>
   local tVar_5

You will get an error on the final line when applying the script as 
tVar_5 has already been implicitly declared as an unquoted literal 
variable.

With Strict Compilation Mode turned on, then neither script will compile 
- as you are using 'tVar_5' on the fifth line without declaring it.

Now, whilst at first site it might seem like 'local' declarations are 
superfluous for these kinds of things, they do actually serve a purpose. 
Compare the following two snippets:

   repeat with x = 1 to 5
     if (x mod 2) is 1 then
       do "put x*x into tVar_" & x
     end if
   end repeat
   local tAllVars
   repeat with x = 1 to 5
     do "put tVar_" & x & " & return after tAllVars"
   end repeat
   put tAllVars

And:

   repeat with x = 1 to 5
     do "local tVar_" & x
     if (x mod 2) is 1 then
       do "put x*x into tVar_" & x
     end if
   end repeat
   local tAllVars
   repeat with x = 1 to 5
     do "put tVar_" & x & " & return after tAllVars"
   end repeat
   put tAllVars

In the first snippet you will get:
   1
   tVar_2
   9
   tVar_4
   25

In the second snippet you will get:
   1

   9

   25

Basically, using 'local' ensures that any use of the variable token will 
be treated as a variable and not as an unquoted literal, i.e. doing 
'local tVar' essentially means add a variable to the current handler 
initialized to empty. If you don't use local then any tokens which have 
not previously been declared as variables (whether at compile time, or 
runtime using do) will be treated as variables with the variable name as 
contents.

Upshot: There's no reason to use 'local' in do if you are initializing 
the variable at that point. Indeed, one could argue that it is better to 
do:

   do "put empty into tVar_" & x

Rather than using 'local' as then you can mix dynamic vars with those 
declared at the point of compilation without issue. (As 'local' requires 
that the variable has *not* been previously defined whether it be as an 
unquoted literal, or as the target of an assignment).

Hope this helps!

Mark.

-- 
Mark Waddingham ~ mark at livecode.com ~ http://www.livecode.com/
LiveCode: Everyone can create apps




More information about the use-livecode mailing list