A Variable is an Attribute that contains a token, and can be set by an
expression that can refer to other variables.
<p>
A variable can be given a token or an expression as its value. To create
a variable with a token, either call the appropriate constructor, or create
the variable with the appropriate container and name, and then call
setToken(). To set the value from an expression, call setExpression().
The expression is not actually evaluated until you call getToken(),
getType(). By default, it is also evaluated when you call validate(),
unless you have called setLazy(true), in which case it will only
be evaluated if there are other variables that depend on it and those
have not had setLazy(true) called.
<p>
Consider for example the sequence:
<pre>
Variable v3 = new Variable(container,"v3");
Variable v2 = new Variable(container,"v2");
Variable v1 = new Variable(container,"v1");
v3.setExpression("v1 + v2");
v2.setExpression("1.0");
v1.setExpression("2.0");
v3.getToken();
</pre>
Notice that the expression for <code>v3</code> cannot be evaluated
when it is set because <code>v2</code> and <code>v1</code> do not
yet have values. But there is no problem because the expression
is not evaluated until getToken() is called. Equivalently, we
could have called, for example,
<pre>
v3.validate();
</pre>
This will force <code>v3</code> to be evaluated,
and also <code>v1</code> and <code>v2</code>
to be evaluated.
<p>
There is a potentially confusing subtlety. In the above code,
before the last line is executed, the expression for <code>v3</code>
has not been evaluated, so the dependence that <code>v3</code> has
on <code>v1</code> and <code>v2</code> has not been recorded.
Thus, if we call
<pre>
v1.validate();
</pre>
before <code>v3</code> has ever been evaluated, then it will <i>not</i>
trigger an evaluation of <code>v3</code>. Because of this, we recommend
that user code call validate() immediately after calling
setExpression().
<p>
If the expression string is null or empty,
or if no value has been specified, then getToken() will return null.
<p>
The expression can reference variables that are in scope before the
expression is evaluated (i.e., before getToken() or validate() is called).
Otherwise, getToken() will throw an exception. All variables
contained by the same container, and those contained by the container's
container, are in the scope of this variable. Thus, in the above,
all three variables are in each other's scope because they belong
to the same container. If there are variables in the scope with the
same name, then those lower in the hierarchy shadow those that are higher.
An instance of ScopeExtendingAttribute can also be used to
aggregate a set of variables and add them to the scope.
<p>
If a variable is referred
to by expressions of other variables, then the name of the variable must be a
valid identifier as defined by the Ptolemy II expression language syntax.
A valid identifier starts with a letter or underscore, and contains
letters, underscores, numerals, dollar signs ($),
at signs (@), or pound signs (#).
<p>
A variable is a Typeable object. Constraints on its type can be
specified relative to other Typeable objects (as inequalities on the types),
or relative to specific types. The former are called <i>dynamic type
constraints</i>, and the latter are called <i>static type constraints</i>.
Static type constraints are specified by the methods:
<ul>
<li> setTypeEquals()
<li> setTypeAtMost()
</ul>
whereas dynamic type constraints are given by
<ul>
<li> setTypeAtLeast()
<li> setTypeSameAs()
</ul>
Static type constraints are enforced in this class, meaning that:
<ul>
<li> If the variable already has a value (set by setToken() or
setExpression()) when you set the static type constraint, then
the value must satisfy the type constraint; and
<li> If after setting a static type constraint you give the token
a value, then the value must satisfy the constraints.
</ul>
A violation will cause an exception (either when setToken() is called
or when the expression is evaluated).
<p>
The dynamic type constraints are not enforced in this class, but merely
reported by the typeConstraints() method. They must be enforced at a
higher level (by a type system) since they involve a network of variables
and other typeable objects. In fact, if the variable does not yet have
a value, then a type system may use these constraints to infer what the
type of the variable needs to be, and then call setTypeEquals().
<p>
The token returned by getToken() is always an instance of the class given
by the getType() method. This is not necessarily the same as the class
of the token that was inserted via setToken(). It might be a distinct
type if the token given by setToken() can be converted losslessly into one
of the type given by setTypeEquals().
<p>
A variable by default has no MoML description (MoML is an XML modeling markup
language). Thus, a variable contained by a named object is not
persistent, in that if the object is exported to a MoML file, the
variable will not be represented. If you prefer that the variable
be represented, then you should use the derived class Parameter instead.
<p>
A variable is also normally not settable by casual users from the user
interface. This is because, by default, getVisibility() returns EXPERT.
The derived class Parameter is fully visible by default.
<p>
In addition, this class provides as a convenience a "string mode."
If the variable is in string mode, then when setting the value of
this variable, the string that you pass to setExpression(String)
is taken to be literally the value of the instance of StringToken
that represents the value of this parameter. It is not necessary
to enclose it in quotation marks (and indeed, if you do, the quotation
marks will become part of the value of the string). In addition,
the type of this parameter will be set to string. In addition,
getToken() will never return null; if the value of the string
has never been set, then an instance of StringToken is returned
that has an empty string as its value. A parameter is
in string mode if either setStringMode(true) has been called or
it contains an attribute named "_stringMode".
<p>
In string mode, the value passed to setExpression(String) may contain
references to other variables in scope using the syntax $id,
${id} or $(id). The first case only works if the id consists
only of alphanumeric characters and/or underscore, and if the
character immediately following the id is not one of these.
To get a simple dollar sign, use $$. In string mode, to set the
value to be the empty string, create a Parameter in the container
that has the value <code>""</code> and then set the string mode
parameter to the <code>$<i>nameOfTheParameter</i></code>. For example,
the parameter might be named <code>myEmptyParameter</code> and have
a value <code>""</code>; the value for the string mode parameter would
be <code>$myEmptyParameter</code>.
Neil Smyth, Xiaojun Liu, Edward A. Lee, Yuhong Xiong
$Id: Variable.java 70402 2014-10-23 00:52:20Z cxh $
Ptolemy II 0.2
Red (neuendor)
Red (cxh)