by
Peter Fritzson,
PELAB - Programming Environment Laboratory
Dept. of Computer and Information Science,
Linköping University, Sweden
An unbound symbol n
n
Bind n to a value
n = 5
Retrieve the value
n
Make n into a constant
SetAttributes[n, {Constant,Protected}]
Try to change the constant
n = 8
The constant is still the same
n
Retrieve the attributes
Attributes[n]
Clear the value and the attributes
Now n has no value, i.e. n is unbound
and has no attributes
Static binding
Static binding is done at compile time, before execution.
Dynamic binding
Dynamic binding is done at run time, during execution.
Mathematica has dynamic binding since it is an interpreted language
A symbol table for a compiled language maps names to static attributes such as type
For example, as in the example below:
SymbolTable[m, Type] = Integer;
SymbolTable[x, Type] = Real;
The whole symbol table
Get the type for the variable n
SymbolTable[m, Type]
The environment in an interpreted language maps names to values and other attributes
begin ... end in Pascal
{ ... } in C
Module[ ... ] in Mathematica
x = 35; (* global x *)
Module[{
x = 999 (* local x *)
},
Print["local x = ", x];
];
Check the global x again:
Scope of a declaration
=
region of the the program over which the bindings established by the declaration are maintained
x = 35; (* global x *)
Module[{
y = 999 (* local level 1, y *)
},
Print["level 1 y = ", y];
Module[{
z = 777 (* local level 2, z *)
},
Print["level 2 z = ", z];
Print["global x = ",x];
];
];
Global x is bound to 35, but y and z are unbound at the global level.
Visibility of a declaration (p 112)
=
visibility includes only those regions where the bindings of a declaration apply
(However, scope may include scope holes (as in Ada))
Visibility by selection (p 112)
e.g.:
example.field
makes field accessible
Inner declarations take precedence
x = 35; (* global x *)
Module[{
x = 999 (* local level 1, x *)
},
Print["level 1 x = ", x];
Module[{
x = 777 (* local level 2, x *)
},
Print["level 2 x = ", x];
];
];
Variables are interpreted according to the reading of the program;
Types can be static
Used by modern languages
x = 35; (* global x *)
p[] := Module[{
},
Print[x];
];
q[] := Module[{
x = 2
},
p[];
];
x = 1;
q[];
Variables are interpreted according to dynamic call chain of functions;
Types cannot in general be static
Used by older languages
Consider the call chain: main > call of q > call of p
Block[] is the Mathematica construct for dynamically scoped blocks.
x = 35; (* global x *)
p[] := Block[{
},
Print[x];
];
q[] := Block[{
x = 2
},
p[];
];
x = 1;
q[];
Always return a value
Pure expressions produce no side effects
z = 66;
x = (y = z)
Lisp, Mathematica, C are expression languages: everything can return a value
Return no value
Produce side effects
z = 66;
z
Applicative (strict) evaluation
=
always evaluate arguments before invoking the operation
(3 + 4)*(5 - 6)
Hold[(3 + 4)*(5 - 6)]//FullForm
Evaluate arguments to the Times operator before calling Times:
False && Print["foo"];
And[True, Print["foo"]]
f[] := Module[{},
x = x+1;
Return[x]
];
p[a_,b_] := Module[{},
Return[b+a]
];
x = 1;
Print[p[f[],x]]
Left to right evaluation order gives 4. Right to left order would give 3.
Both sq and sq2 uses normal-order evaluation.
g[x_Integer,y_Integer] := Plus[x,y];
g[x_Real,y_Real] := Plus[1000.,x,y];
g[x_List,y_List] := Union[x,y];
Invoking the integer version
g[3,5]
Calling the real version
g[3.,5.]
A version with mixed integer and real arguments is not defined. g is not called. The call remains unevaluated.
Calling the set union version
Defining a mixed integer/real version
g2[x:(_Real | _Integer), y_Real] := Plus[500.,x,y];
g2[3, 55.]
g2[3., 55.]