Type Casting and the Local Protocol
While a script is being compiled, the Mathscript statements in the script are
translated into LISP statements. Mathscript is a strongly typed language, and Lisp has no types at all. Thus, the compiler attempts to determine from
the syntax of the statements, what the semantics (LISP translation) should be.
As it is in ordinary language, meaning depends very much on context.
Thus, for example, the statement:
make f(x) x^2 will normally be interpreted to mean: Create a function called f that squares the value of its argument. On the other hand, if f is already the name of a vector, and if x has value 3, then the same statement would mean: Set the third component of
the vector f to 9. Here f(x) is interpreted as an indexed vector form.
The compiler has no trouble with this semantic ambiguity if object f is global, but difficulties may arise in common situations in which it is not practical
to make all relevant objects global.
For example, suppose one creates the vector v by:
make v [ [1,2], [3,4] ]. Then v(1) is itself a vector, but the compiler does not know that. Consider the
following button script:
let v be getpoints(true,2);
let vector #2 u be v(1);
set entry 1 1 u(1);
As it stands, it will not compile, because while v is of vector #2 type, v(1) is of expression type, and the compiler refuses to set a 2 dimensional vector to an expression. We know that v(1) is a vector, but the compiler does not. A possible solution is to modify the
second line, so that we do not require u to be a vector:
let v be getpoints(true,2);
let u be v(1);
set entry 1 1 u(1);
Now, the compiler complains that u(1) is meaningless because u is an expression, not a function or vector. In situations like this, it is
necessary to "help" the compiler. Now the following script works fine:
local (ve #2 u) {
let v be getpoints(true,2);
let u be v(1);
set entry 1 1 u(1);
}
We have finessed the question of the type of v(1). It is an expression. But with the local block we have declared a local object: u whose type is vector #2. This has the effect of telling the compiler, whenever it checks the type of
u within the block, that u is a 2 dimensional vector. While the third line created a true local object u (of type expression), the fourth line caused the compiler to override the actual type of this
local object, and to use the locally declared type for u.
Thus, when a local block is created, certain types are declared for object names, but no (local or
global) objects are actually created. If later in the script, objects with those
names are created (using make or let), or if global objects with those names are referred to, the type given in the local declaration is
used by the compiler. It overrides the actual type. This is called type casting, and it is a common and necessary strategy in scripting.
Local blocks serve another purpose as well. If there was a global object with the same name as one declared in a local block, the object would have
its current global value when the block was entered. Whatever happens to the
global object within the block is entirely forgotten when the block is exited.
The object is left with whatever value it had when the block was entered. Thus,
local blocks give a safe way to manipulate global objects without changing
them permanently. This is precisely the same as lambda-binding .