Difference between revisions of "Expression Syntax"

 
(31 intermediate revisions by 5 users not shown)
Line 1: Line 1:
Analytica expressions appear primarily in the Definition and Check attributes of variable objects.
+
[[Category: Styles and options]]
 +
[[Category: Typescript Commands]]
 +
[[Category: Expressions]]
  
Note that Analyica [[Scripting|Typescript]] has a separate syntax from Analytica Expressions (see also [[Typescript_Commands]]). Typescript is used in the Script attribute of Button and Picture nodes, from the Typescript window in Analytica, and from the CAEngine::SendCommand method in ADE.  However, expressions can be evaluated from typescript as well with some caveats - see [[Scripting]].
+
Analytica expressions are the language used for [[Definition]] attributes of a variable or [[User-Defined_Functions|Function]]. Expressions are also used in the [[Check]], [[OnClick]], and [[OnChange]] Attributes.
  
= Function Calls =
+
== Function Calls ==
 +
You can call [[Alphabetical_Function_List | built-in functions]] and [[User-Defined Functions]] using standard ''position-based'' syntax, in which you specify the parameters (or arguments) in sequence between parentheses:
  
Analytica contains many [[Alphabetical_Function_List | built-in functions]], and you can extend these with [[User-Defined Functions]].  The standard ''position-based'' syntax for the parameters of a function is:
+
:<code>Uniform(0, B, True)</code>
  
F(A, B, C)
+
Each actual parameter, <code>5, B</code>, and <code>True</code> in this example, may be a number, variable, array, or or other expression, depending on the type of parameter expected. In this case, the function [[Uniform]] expects parameters («min», «max», «integer»).
  
where the parameter values A, B, and C may themselves be expressions. 
+
You can also specify some or all parameters using a ''name-based'' syntax, in which you specify a parameter by name, followed by ":" and the value to be called, for example:
  
For most, but not all, built-in functions and all [[User-Defined Functions]], you can also used a ''name-based'' syntax for parameters.  These examples show four ways to call function [[Uniform]] with the same parameter values, using position-based syntax, name-based syntax, and a combination:
+
:<code>Uniform(min: 1, max: 100, integer: True)</code> -- same parameter positions as normal
 +
:<code>Uniform(integer: True, min: 1, max: 100)</code> -- a different sequence is fine with named parameter
 +
:<code>Uniform(1, 100, integer: true)</code> -- mixed syntax: initial parameters are position based, last is by name.
  
Uniform(1, 100, true)  --- position-based syntax
+
With names, you can list the parameters in any order, as in the second example. Using mixed syntax, you can specify initial parameters by position, followed by one or more parameters identified by name. This is especially useful when calling a function with one or a few required initial parameters followed by multiple optional parameters of which you only want to specify a few.
  Uniform(min:1, max:100, integer: true)  --- name-based syntax
 
Uniform(Integer: true, min:1, max: 100)  --- name-based syntax
 
Uniform(1, 100, integer: true)  --- mixed syntax
 
  
Name-based syntax means you specify the parameter by name, followed by colon, followed by the a number or expression giving its value. When you specify parameters by name, you can list them in any order, as in the third exampleUsing mixed syntax, you can specify initial parameters by position, but after you specify a parameter by name, you must also specify all following parameters by name.
+
Some parameters expect an index (or variable), in which case you must provide the identifier of an Index (or other variable). You can specify an index using the [[Dot_operator::A.I#Dot_Operator:_A.I|dot-operator]] syntax -- e.g. <code>A.I</code>In these cases, you may not use arbitrary expressions, including function calls, as the value.
  
If a function expects a parameter to be an index or variable, you must give it the identifier of a variable or index. You can specify an index using the [[Dot_operator::A.I#Dot_Operator:_A.I|dot-operator]] syntax -- e.g. A.I.  But, in these cases, you may not use arbitrary expressions, including function calls, as the value.
+
There are many other expectations or restrictions on parameters and how they get evaluated (or not), specified by [[Function Parameter Qualifiers|parameter qualifiers]] and on the [[Evaluation Modes|evaluation mode]] when the function is evaluated. You can see these qualifiers in the documentation, or in the Object view for each Function. You can also specify them yourself in [[User-defined functions]] that you define yourself.
  
Functions evaluate ("call") their parameters in various ways, as specified by the[[Function Parameter Qualifiers|parameter qualifiers]], and on the [[Evaluation Modes|evaluation mode]] when the function is evaluated.
+
== Array subscripting ==
  
= Operator Precedence =
+
Analytica is unusual among computer languages in using '''Named Index subscripting'', meaning that you specify which index to subscript in an array by naming the index, rather than by some sequence of indexes.  For example, suppose array <code>Population</code> is indexed by <code>Year</code> and <code>State</code>, you can get the population of New York in 2010 as:
 +
:<code>Population[Year = 2010, State = "New York"]</code>
 +
 
 +
or equivalently:
 +
:<code>Population[State = "New York", Year = 2010]</code>
 +
 
 +
'''Named Index subscripting''' has big advantages  for multidimensional arrays over conventional positional indexing, which is what most other computer languages use. First, you don't have to remember which is index is "inner" or "outer". In fact, those concepts are usually irrelevant in Analytica.  Second,  you can slice out a subarray, e.g.
 +
:<code>Population[State = "New York"]</code>
 +
 
 +
gives the population of New York for every value of Year. Or:
 +
:<code>Population[Year = 2010]</code>
 +
 
 +
gives the population of all states for 2010.
 +
 
 +
As you develop a model and add, or remove detail, the number of dimensions in an array may change.  Sometimes, as in parametric analysis where you replace a single input value by a list of alternative values, the number of dimensions may change even as you run a model.  Accessing Indexes by name is much more robust -- it won't break if an array gets an extra dimension, as would standard positional indexing.
 +
 
 +
Analytica simply ignores a subscript using by an index that the array doesn't contain:
 +
:<code>Population[State = "New York", Year = 2010, Month = "February"]</code>
 +
 
 +
just returns the population for New York in 2010. It implicitly assumes the population is the same for every month of that year. This is an important general Principle -- '''Constant over Irrelevant Indexes'''.
 +
 
 +
If you subscript an array using a value that's not in that Index, it will usually flag an error and return [[Null]]:
 +
:<code>Population[State = "Quebec"]  &rarr; NULL</code>
 +
 
 +
You can specify an alternative value to return for an invalid index value:
 +
:<code>Population[State = "Quebec", defValue: 0]  &rarr; 0</code>
 +
 
 +
== Operator Precedence ==
 +
Analytica uses a fairly standard precedence for arithmetic and logical operators. Exponentiation (^) binds more tightly than multiplication (*) and division (/), which binds more tightly than addition (+) and subtraction (-).  Thus, this expression
 +
:<code>1/2*3 - 4/5^6 + 7</code>
  
Some operations in Analytica are parsed with a higher binding precedence than other operators.  For example, exponentiation (^) binds more tightly than multiplication (*) and division (/), which binds more tightly than addition (+) and subtraction (-).  Therefore, the following expression
 
1 / 2 * 3 - 4 / 5 ^ 6 + 7
 
 
would parse as
 
would parse as
( ( 1 / 2 ) * 3 ) - ( 4 / ( 5 ^ 6 ) ) + 7
+
:<code>((1/2)*3) - (4/(5^6)) + 7</code>
  
The following list shows the binding precedence of Analytica operators, with the highest precedence operators at the topThose operators in the same bullet have the same level of precedence:
+
This list shows the binding precedence of Analytica operators, with the highest precedence operators firstOperators in the same bullet have the same level of precedence:
  
 
* Parentheses: ( ... )
 
* Parentheses: ( ... )
 
* Function calls
 
* Function calls
 
* [[Logical Operators#Not|Not]]
 
* [[Logical Operators#Not|Not]]
* [[Index_Position_Operator::%40 | @I ]], [[Reference_Operator::%5C | \A]], [[Reference_Operator::%5C | \[I]A]], [[Dereference Operator|#R]].
 
 
* [[Dot_operator::A.I|A.I]]
 
* [[Dot_operator::A.I|A.I]]
 +
* [[COM Integration#methodSyntax|A->method()]], [[COM Integration#propertySyntax|A->propetry]]
 
* [[Subscript/Slice Operator | A[I=x] ]]
 
* [[Subscript/Slice Operator | A[I=x] ]]
 +
* [[Index_Position_Operator::%40 | @I ]], [[Reference_Operator::%5C | \A]], [[Reference_Operator::%5C | \[I]A]], [[Dereference Operator|#R]].
 
* [[Attrib of Obj]]
 
* [[Attrib of Obj]]
 
* ^
 
* ^
Line 45: Line 75:
 
* +, - (binary minus)
 
* +, - (binary minus)
 
* [[Sequence Operator|m..n]]
 
* [[Sequence Operator|m..n]]
* =, <=, >=, <, >, <>
+
* [[Comparison Operators|=, <=, >=, <, >, <>]]
* [[Logical Operators#And|And]], [[Logical Operators#Or|Or]]
+
* [[Logical Operators#And|And]]
 +
* [[Logical Operators#Or|Or]]
 +
 
 
* [[Text_Concatenation_Operator:_%26 | &]]
 
* [[Text_Concatenation_Operator:_%26 | &]]
 
* [[Assignment_Operator::_::%3D | :=]]
 
* [[Assignment_Operator::_::%3D | :=]]
* If..Then..Else, Ifall..Then..Else, IfOnly..Then..Else
+
* [[If-Then-Else|If..Then..Else]], [[Ifall-Then-Else|Ifall..Then..Else]], [[Ifonly-Then-Else|IfOnly..Then..Else]], [[While..Do]], [[Local..Do]], [[Var..Do]], [[LocalAlias..Do]], [[For..Do]]
 
* sequence of statements (;), comma separation of elements or parameters (,)
 
* sequence of statements (;), comma separation of elements or parameters (,)
  
= Comments =
+
== Comments ==
 +
Comments can be embedded anywhere whitespace would be allowed within an expression.  There are two ways to specify comments:
  
Comments can be embedded anywhere whitespace would be allowed within an expression.  There are two recognized syntaxes for comments:
+
:<code>{ This is a comment }</code>
 +
:<code>/* This is a comment */</code>
  
{ This is a comment }
+
If you start a comment with "{", your comment cannot contain the "}" character. Similarly, if you start a comment with "/*", it musn't contain the two character sequence "*/".  If you want to nest comments, for example to temporarily comment out some code that already contains comments, use <code>{...}</code> for the inner comment and <code>/*...*/</code> for the outer comment, or vice versa.
  /* This is a comment */  
 
  
If you start a comment with {, then your comment cannot contain the } character within. Similarly, if you begin a comment with /*, the comment cannot contain the two character sequence */ insideIf you need to embed a comment within a comment (which sometimes is useful when temporarily commenting out a block of expression code that already contains comments), then you need to ensure that if the inner comment uses {...}, that the outer comment uses /*...*/, or vise versa.  
+
=== Version Gated Comments ===
 +
A version-gated comment contains code that Analytica ignores as a comment in some releases of Analytica, but treats as meaningful code in other releases  For example, suppose you have an algorithm that uses features new in Analytica 5.0, but you still want it to work with Analytica 4.6, perhaps falling back to a less efficient algorithm or to reduced functionalityA version-gated comment lets you do this without risk of parse errors in the version that might not recognize the newer features.
  
== Version Gated Comments ==
+
Consider these equivalent forms of version gated comments:
 +
:<code>{!50000|''expression''}</code>
 +
:<code>{!50000-|''expression''}</code>
  
(new to 4.0)
+
Analytica release 5.00.00 or after will interpret the expression, but prior releases will ignore it as a comment. 
  
A version-gated comment is a portion of an expression that is viewed as a comment in some releases of Analytica, but as an actual expression in other releases of Analytica. For example, suppose you have an algorithm that leverages features that are new to Analytica 4.0, but you still want the algorithm to be usable by users of Analytica 3.1, perhaps falling back to a less efficient algorithm or to reduced functionality.  A version-gated comment provides one way to do this without risk of parse errors in the version that might not recognize the newer features.
+
This gated comment executes the expression in releases 5.00.00 through 5.01.00, but releases before and after will treat it as a comment:
 +
:<code>{!50000-50100|''expression''}</code>
  
Consider the following equivalent forms of version gated comments.
+
This version interprets the expression in any release from 4.0 up to 5.02.00, but any release thereafter treats it as a comment: 
{!40000|''expression''}
+
:<code>{!-50200|''expression''}</code>
{!40000-|''expression''}}
 
  
These indicate that in Analytica release 4.00.00 or after, the expression is to be interpreted, but in any release prior to Analytica 4.00.00, it should be treated as a comment.
+
Another way to accomplish the same thing is to use the [[AnalyticaVersion]] system variable in an expression.
 +
:<code>[[If]] [[AnalyticaVersion]]>=50000 [[Then]] «expression1» [[Else]] «expression2»</code>
 +
But, if either expression uses a function that doesn't exist in the earlier release, then the expression won't parse, in which case you need to use a gated comment.
  
The following version gated comment treats this as a comment in any release prior to 4.00.00 or after 4.01.00, but in releases 4.00.00 through 4.01.00, the expression is interpreted:
+
== Script syntax ==
{!40000-40100|''expression''}
+
The obsolete [[Script]] attribute uses  [[Scripting|Typescript]], which has a slightly different syntax from Analytica Expressions (see also [[:Category:Typescript_Commands|Typescript Commands]]). The Script attribute was replaced by [[OnClick]] and [[OnChange]] attributes in [[Analytica 4.6]] release, and is retained only for backward compatibility.
  
The following interprets the expression in any 4.0 or later release that is prior to or including 4.02.00, but treats it as a comment in any release after 4.02.00. 
+
== History ==
{!-40200|''expression''}
+
* All version-gated comments are treated as comment in Analytica release 3.1 and earlier, regardless of what the version number indicates, since the version-gated comment feature was not introduced until Analyica 4.0.
  
'''''Important:''''' All version-gated comments are treated as comment in Analytica releases 3.1 and earlier, regardless of what the version number indicates, since the version-gated comment feature was not introduced until Analyica 4.0.
+
==See Also==
 +
* [[Expressions]]
 +
* [[Expression Assist]]
 +
* [[The Expression popup menu]]
 +
* [[Parsed Expressions]]
 +
* [[Expressions that don't array-abstract]]
 +
* [[Definitions]]
 +
* [[User-Defined Functions]]
 +
* [[Function calls and parameters]]
 +
* [[:Category:Typescript_Commands|Typescript Commands]]
 +
* [[AnalyticaVersion]]

Latest revision as of 17:04, 7 June 2018


Analytica expressions are the language used for Definition attributes of a variable or Function. Expressions are also used in the Check, OnClick, and OnChange Attributes.

Function Calls

You can call built-in functions and User-Defined Functions using standard position-based syntax, in which you specify the parameters (or arguments) in sequence between parentheses:

Uniform(0, B, True)

Each actual parameter, 5, B, and True in this example, may be a number, variable, array, or or other expression, depending on the type of parameter expected. In this case, the function Uniform expects parameters («min», «max», «integer»).

You can also specify some or all parameters using a name-based syntax, in which you specify a parameter by name, followed by ":" and the value to be called, for example:

Uniform(min: 1, max: 100, integer: True) -- same parameter positions as normal
Uniform(integer: True, min: 1, max: 100) -- a different sequence is fine with named parameter
Uniform(1, 100, integer: true) -- mixed syntax: initial parameters are position based, last is by name.

With names, you can list the parameters in any order, as in the second example. Using mixed syntax, you can specify initial parameters by position, followed by one or more parameters identified by name. This is especially useful when calling a function with one or a few required initial parameters followed by multiple optional parameters of which you only want to specify a few.

Some parameters expect an index (or variable), in which case you must provide the identifier of an Index (or other variable). You can specify an index using the dot-operator syntax -- e.g. A.I. In these cases, you may not use arbitrary expressions, including function calls, as the value.

There are many other expectations or restrictions on parameters and how they get evaluated (or not), specified by parameter qualifiers and on the evaluation mode when the function is evaluated. You can see these qualifiers in the documentation, or in the Object view for each Function. You can also specify them yourself in User-defined functions that you define yourself.

Array subscripting

Analytica is unusual among computer languages in using 'Named Index subscripting, meaning that you specify which index to subscript in an array by naming the index, rather than by some sequence of indexes. For example, suppose array Population is indexed by Year and State, you can get the population of New York in 2010 as:

Population[Year = 2010, State = "New York"]

or equivalently:

Population[State = "New York", Year = 2010]

Named Index subscripting has big advantages for multidimensional arrays over conventional positional indexing, which is what most other computer languages use. First, you don't have to remember which is index is "inner" or "outer". In fact, those concepts are usually irrelevant in Analytica. Second, you can slice out a subarray, e.g.

Population[State = "New York"]

gives the population of New York for every value of Year. Or:

Population[Year = 2010]

gives the population of all states for 2010.

As you develop a model and add, or remove detail, the number of dimensions in an array may change. Sometimes, as in parametric analysis where you replace a single input value by a list of alternative values, the number of dimensions may change even as you run a model. Accessing Indexes by name is much more robust -- it won't break if an array gets an extra dimension, as would standard positional indexing.

Analytica simply ignores a subscript using by an index that the array doesn't contain:

Population[State = "New York", Year = 2010, Month = "February"]

just returns the population for New York in 2010. It implicitly assumes the population is the same for every month of that year. This is an important general Principle -- Constant over Irrelevant Indexes.

If you subscript an array using a value that's not in that Index, it will usually flag an error and return Null:

Population[State = "Quebec"] → NULL

You can specify an alternative value to return for an invalid index value:

Population[State = "Quebec", defValue: 0] → 0

Operator Precedence

Analytica uses a fairly standard precedence for arithmetic and logical operators. Exponentiation (^) binds more tightly than multiplication (*) and division (/), which binds more tightly than addition (+) and subtraction (-). Thus, this expression

1/2*3 - 4/5^6 + 7

would parse as

((1/2)*3) - (4/(5^6)) + 7

This list shows the binding precedence of Analytica operators, with the highest precedence operators first. Operators in the same bullet have the same level of precedence:

Comments

Comments can be embedded anywhere whitespace would be allowed within an expression. There are two ways to specify comments:

{ This is a comment }
/* This is a comment */

If you start a comment with "{", your comment cannot contain the "}" character. Similarly, if you start a comment with "/*", it musn't contain the two character sequence "*/". If you want to nest comments, for example to temporarily comment out some code that already contains comments, use {...} for the inner comment and /*...*/ for the outer comment, or vice versa.

Version Gated Comments

A version-gated comment contains code that Analytica ignores as a comment in some releases of Analytica, but treats as meaningful code in other releases For example, suppose you have an algorithm that uses features new in Analytica 5.0, but you still want it to work with Analytica 4.6, perhaps falling back to a less efficient algorithm or to reduced functionality. A version-gated comment lets you do this without risk of parse errors in the version that might not recognize the newer features.

Consider these equivalent forms of version gated comments:

{!50000|expression}
{!50000-|expression}

Analytica release 5.00.00 or after will interpret the expression, but prior releases will ignore it as a comment.

This gated comment executes the expression in releases 5.00.00 through 5.01.00, but releases before and after will treat it as a comment:

{!50000-50100|expression}

This version interprets the expression in any release from 4.0 up to 5.02.00, but any release thereafter treats it as a comment:

{!-50200|expression}

Another way to accomplish the same thing is to use the AnalyticaVersion system variable in an expression.

If AnalyticaVersion>=50000 Then «expression1» Else «expression2»

But, if either expression uses a function that doesn't exist in the earlier release, then the expression won't parse, in which case you need to use a gated comment.

Script syntax

The obsolete Script attribute uses Typescript, which has a slightly different syntax from Analytica Expressions (see also Typescript Commands). The Script attribute was replaced by OnClick and OnChange attributes in Analytica 4.6 release, and is retained only for backward compatibility.

History

  • All version-gated comments are treated as comment in Analytica release 3.1 and earlier, regardless of what the version number indicates, since the version-gated comment feature was not introduced until Analyica 4.0.

See Also

Comments


You are not allowed to post comments.