Difference between revisions of "Expression Syntax"

(Rewrite of function syntax section)
 
(32 intermediate revisions by 5 users not shown)
Line 1: Line 1:
= Function Calls =
+
[[Category: Styles and options]]
 +
[[Category: Typescript Commands]]
 +
[[Category: Expressions]]
  
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:
+
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.
  
F(A, B, C)
+
== 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:
  
where the parameter values A, B, and C may themselves be expressions. 
+
:<code>Uniform(0, B, True)</code>
  
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:
+
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»).
  
Uniform(1, 100, true)  --- position-based syntax
+
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)  --- 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 example.  Using 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.
+
:<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.
  
If a function expects a parameter to be an index or variable, you must give it the identifier of a variable or indexYou 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.
+
With names, you can list the parameters in any order, as in the second exampleUsing 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.
  
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.
+
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.
  
= Operator Precedence =
+
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.
 +
 
 +
== 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 <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 41: 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 can be embedded anywhere whitespace would be allowed within an expression.  There are two ways to specify comments:
 +
 +
:<code>{ This is a comment }</code>
 +
:<code>/* This is a comment */</code>
 +
 +
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.
 +
 +
=== 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:
 +
:<code>{!50000|''expression''}</code>
 +
:<code>{!50000-|''expression''}</code>
 +
 +
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:
 +
:<code>{!50000-50100|''expression''}</code>
 +
 +
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: 
 +
:<code>{!-50200|''expression''}</code>
 +
 +
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.
 +
 +
== Script syntax ==
 +
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.
 +
 +
== 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==
 +
* [[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.