4.3 Static and Dynamic References

Requirement for Static Set and Table Names in Basic Operations

The Aspen SCM Expert System interpreter resolves references to the names
of sets and tables and to elements of sets when the rule is
semi-compiled (i.e. as the interpreter is about to execute the rule for the first time after linking). It accepts variables as the values of row or column
elements but not as the name of a set or table. Thus

IF ?VALUE = ?TABLE(?ROW,?COL)

is not acceptable (?TABLE is unacceptable as a variable name for
the table) but

IF ?VALUE = MYTABLE(?ROW,?COL)

is OK.

Preference for Dynamic References to Set Elements

Note, however, that

IF ?VALUE = MYTABLE(ROW1,COL3)

may also be unacceptable if, at the time when the rule is
semi-compiled (i.e. when the interpreter starts running the rule), either
ROW1 or COL3 does not lie in the row- or column-sets respectively of
MYTABLE.

Where the row or column sets are built dynamically (or their
members differ between sites where a program is run) this often makes
it necessary to use variables to reference the row or column of a
table. Thus code such as:

is unacceptable (because the column VAT exists only in the British
case while the columnTVA exists only in the French one). Even
though the code would work when run (because the reference to VAT
would only be executed in the case which contained the column set
entry VAT; and likewise for TVA), the semi-compiler rejects this
because it cannot resolve the reference to VAT in the French case or
to TVA in the British case.

Even where static references appear to work, it is safer to use a
dynamic reference if SORT operations are performed on the set to
which the static reference belongs (this includes SORTs on tables
indexed by the set). Under some circumstances (the precise conditions
have not been established but appear to include many SORTs) the
interpreter appears to lose track of the current location of the
static reference in the set and uses an apparently random one
(possibly the position which it had when the rule was linked). It
thus accesses a different location from that which it should, causing
unexpected behaviour.

Another place where static references are unacceptable is when testing for membership of a set. Even if VAT is a member of the set TABLE.H it is unacceptable to write

AND "VAT" IN TABLE.H

Instead you must write:

AND ?TAXCOL = "VAT"AND ?TAXCOL IN TABLE.H

Language Constructs Accepting Dynamic References to Sets and Tables

Much of the Aspen SCM Expert System language
accepts dynamic references to sets and tables. The following
constructs do:

?MYVAR IN ?MYSET - either as a loop (if ?MYVAR is FREE) or as a test (if ?MYVAR is bound)

?CODE = CODEOF ?MYSET(?INDEX)

?INDEX = INDEXOF ?MYSET(?CODE)

?VALUE = MAXVAL ?MYTABLE(?ROW,?COLUMN)

?VALUE = MINVAL ?MYTABLE(?ROW,?COLUMN)

?SIZE = SETCOU ?MYSET

?SIZE = SETMAX ?MYSET

?SIZE = SIZEOF ?MYSET

Note in particular that the loop constructs work. Thus you can
write

AND FREE ?MYCODEAND ?MYCODE IN ?MYSETAND ?MYINDEX = INDEXOF ?MYSET(@)

to loop over an arbitrary set and get the value of the index. With
this you can then use CODEOF to get the Code and DESCOF to get the
Description.

More generally you can find the Description of an arbitrary Code
for a dynamic set using

Substitutes for Dynamic References which Do not Work

However, other language constructs, often the most basic, do not accept
dynamic references to sets or tables, at least not as the location
where the result is to be placed. Thus

IF ?MYSET = "FRED"AND ?MYSET = 0

does not null the set FRED. Instead it sets the local variable
?MYSET first to FRED and then to 0.

For some of these language constructs (but not nulling a set) there are
equivalent Aspen SCM commands which can be used instead. If you are using
versions of Mimi before 6.0, you must ensure that such commands are
included in $NOPRED and that $NOPRED has been hashed (which happens
automatically if you edit $NOPRED).

COPY
?MYTABLE1 INTO ?MYTABLE2 (but remember to copy the row- and
column-sets first)

MYSET(INDEX)
= ?MYNUM

SETIND ?MYSET
= ?MYNUM

If you have a set with zero elements, NULLSET, you can null other
sets by using the statement

COPY
NULLSET INTO ?MYSET

but this causes ?MYSET to acquire the characteristics of NULLSET,
i.e. its lengths of Code and Description, Type and maximum number of
elements. A better way to null a set is to use the MODIFY command:

MODIFY
?MYSET COUNT = 0

A problem with dynamic Aspen SCM commands is that they
are processed in a buffer which is about 80 characters long. This
means that a command may fail because its syntax is invalid when it
is truncated to the buffer length, e.g. a character string which is
enclosed in quotes may lose its trailing quote and become
meaningless.

Retrieving Values from Dynamic Tables

Values can be retrieved from dynamic sets using INDEXOF,
CODEOF and DESCOF and by looping (see above). Retrieving values from dynamic tables is more difficult. The AMPSET command provides a mechanism:

Care needs to be taken here, because all amper variables are
character so ?VALUE will be character even if ?MYTABLE contains
numeric data. In such cases the statement

AND ?VALUE = ?VALUE + 0

should be added to convert ?VALUE to numeric data type so that
comparisons (especially with 0) will work as expected.

Note, however, that the use of dynamic Aspen SCM commands such as FILL
and AMPSET is inefficient. If there are more than a few such
assignments it may well be better to operate on a scratch set or
table in the rule and move the data into it at the beginning and copy
the data back out at the end.

Using TCHOSEN as a Scratch Table

A very useful scratch table is TCHOSEN
which is automatically reformatted, along with its row and column
sets TCHOSENR and TCHOSENC by a SELECT statement. However, its very
usefulness carries with it dangers. It is liable to be used in many
rules so if it is referenced in a loop which calls another rule, it
may well have been changed before the loop terminates.

One problem which arises out of TCHOSEN’s ubiquity is that while
the syntax for referencing it is usually TCHOSEN(?ROW,?COL) it can
have a third argument, i.e. TCHOSEN(?ROW,?COL,?CHARS) if it is a
string or panel table. Which is correct is determined at run-time as
the interpreter enters the rule with the reference (i.e. the
interpreter uses late binding for this rather than LINK-time binding
when testing for static references to elements of sets).

It is therefore inadequate simply to execute a SELECT statement on
a string or panel table and then reference TCHOSEN(?ROW,?COL,?CHARS).
Instead the SELECT statement must either be executed in a jacket
routine before entering the rule which accesses TCHOSEN with three
arguments or a dummy SELECT statement must be executed on a string or
panel table before entering the rule. The same applies in reverse if
TCHOSEN is to be referenced with two arguments after a SELECT
statement on a string or panel table.

Tokens which End with a Variable

A curious feature of the interpreter is that if a token which
appears on the right hand side of an assignment ends with (but does
not consist wholly of) the name of a local or global variable, the
interpreter will substitute the variable’s value and then pass the
result to the command interpreter. Thus statements such as