The autocalc variable controls the evaluation scheme of the EDEN interpreter.
When it is 1 (default) or non-zero, the interpreter will try to evaluate
all definitions (if they are evaluable, i.e. all their source variables
are defined); otherwise (autocalc is zero) the interpreter puts the suspended
definitions in a queue.
Before the interpreter evaluates a definition, it tests whether all its source variables are defined, i.e. their UpToDate flags are true. However, the interpreter is not intelligent enough to identify variables referenced by a definition indirectly. For instance,
func F { para N; return N + Z; }
Y is F(1);
Function F references the (global) variable Z,
but the interpreter does not know about that. When Y
is defined, the interpreter thinks that Y depends on
F only, and proceeds to evaluate Y and thus
evaluate F. However, F finds that Z
is undefined. In this example, F returns the sum of
Z and the first parameter which produces @
when Z is @ However, some operators and most of
the statements produce an error when the expected data types are not met.
Of course, if we defined Z before the introduction of
Y, it may not cause an error. However, if we introduce
Z after that of Y, we are in the risk.
Hence, the result of computation seems to be sensitive to the order of
definitions. Despite of this ordering problem, redefining Z
would not cause Y to be updated. This may not be the
intended behaviour sometimes. There are two ways to get around it:
autocalc to 0 before the introduction of all definitions. After
all definitions are defined, set autocalc to 1 again. By doing so, the
evaluation of definitions is delayed. For instance,
autocalc = 0;
/* ... other statements ... */
func F { para N; return N + Z; }
Y is F(1);
Z is 10;
/* ... other statements ... */
autocalc = 1;
However, this method does not solve the re-evaluation problem.
Z to F. For example,
func F { para N; return N + Z; }
proc touch_F : Z { touch(&F); }
Y is F(1);
Z is 10;
Because now change of Z will induce a change to
F, Y is indirectly dependent
upon Z, and Y can't be evaluated until Z is defined. Also Y will be re-evaluated
when Z is re-defined. This point is not true for the former solution.
In fact, the interpreter should generate such dependency for function
specifications.
func F: Z { para N; return N + Z; }
or
func F { para N; return N + Z; }
Z ~> [F]
to impose dependency would not work because in both cases a change of
Z will call the function F (as if it is an action). This is an error
because a parameter is needed to calculate F.