Function parameter qualifiers
Parameter qualifiers are keywords used in the Parameters attribute of a function to specify what kind of value or object the function expects:
- Class Qualifiers, such as Index and Variable, specify what class of Object is expected.
- Evaluation mode qualifiers, such as Mid and Prob, control whether to evaluate a parameter as deterministic or probabilistic.
- Data type qualifiers, such as Number, Text, Reference, and Handle, specify the expected data type.
- Dimension qualifiers, such as Atom, List, Array, and [i], specify the expected dimensions and indexes to support array abstraction.
- Optional (or = with default) and Repeated (or ...) specify whether a parameter is optional or may be repeated.
Why use qualifiers?
Parameter qualifiers help make sure that each parameter gets the kind of value or object that the function expects. A Class qualifier specifies the expected class (Index, Variable, or other object class). An Evaluation mode qualifier specifies whether to evaluate the parameters as deterministic (Mid) or probabilistic (Prob). A Data type qualifier specifies whether the parameter should be a number, text, Boolean, or other data type. A Dimension qualifier specifies whether a parameter should be a single value, e.g. a scalar number, or an array, and how many indexes it should have.
When the actual parameter does not match what the qualifier(s) specify, Analytica will try to convert it to the expected form. For example. it can reduce a high-dimensional array down to arrays with fewer dimensions or a scalar with no dimensions if that's what the function expects the parameter to be. If a value contains a number, but parameter expects a text, it may be able to coerce (convert) the number to a text. When it can't convert it, it flags an error. In this way, qualifiers are very helpful in avoiding errors in function calls, or at least in detecting and reporting them.
Built-in functions use qualifiers extensively to avoid or detect mismatches between formal and actual parameters. See the Syntax segment, to see what the function expects from its parameters. When you write your own User-Defined Functions, It's a good idea to use qualifiers for any parameter that the function requires to be of a particular class, data type, or dimensions.
By convention, formal parameters (e.g. «a», «i», «o») start with a lowercase letter, global variables and functions (e.g.
F, Y, J) start with an uppercase letter, and qualifiers also start with an uppercase. Analytica doesn't enforce this convention, but it helps clarity in reading functions and models.
For example, consider a Function F with Parameters specified as:
Parameters: (a: Array Number; i: Index; o: Optional Boolean = False)
We may call the function in an expression as:
F(Y^2, J, True)
The parameters, «a», «i», and «o», in the Parameters attribute are termed the formal parameters. The parameters,
1 in the call to Function F are termed the actual parameters.
The qualifiers, Array Number, after formal parameter «a», require that the actual parameter
Y^2 should evaluate to an array of numbers. Parameter
J should be an Index variable. And «o» should evaluate to a Boolean (or a number that will be treated as a Boolean, i.e., 0 is False and all other numbers are
True.) Parameter «o» is optional and defaults to
True, if the call to the function has no actual parameter.
Object Class Qualifiers
These Qualifiers, including Index, Variable, and Object, specify that the parameter to be the identifier of an object of that class. Within the function, the parameter contains a Handle to the object. It does not evaluate the parameter during the call. The function can operate on the object, including getting an attribute (or assigning to an attribute if the function is called from a script.)
Requires the parameter to be the identifier of an Index. It may be a global or local Index. The function does not evaluate the Index when it is called, and can use the parameter as an index in internal expressions, for example:
Parameters: (x: Number; i: Index)
Definition: x/Sum(x, i)
A parameter with Index Qualifier must be the identifier of a Variable, but its class doesn't have to be Index. It also works for other classes of variables if their Domain is an Index, Discrete, or defined as a List. It also works for a local Index declared as an Index within the Definition calling the function. And it can accept the syntax
A is an array with a local index
As you might expect, a parameter qualified as Variable, should be the identifier of a Variable.
[MH: Should we call this Object, since it can refer to any class of Analytica object, not just a Variable? Or would it be better to offer a several such qualifiers, to specify what Class of Object is acceptable? E.g. Module (any module type, including Model, Module, Library), Variable (any Variable type, including Index, Constant, Chance, Decision, and Variable), or Object, that allows an Object of any class. Alternatively, we could add Object <Class>, where <class> can be any Analytica class. Should or could you be able to pass an Attribute, or User-defined Function, or System Function to an Object parameter?]
[MH: Please review changes below]
The actual parameter passed to a Variable parameter must be one of:
- An identifier of an object in the global namespace.
Xholds an array and
Iis the identifier of an index of that array.
- A local variable identifier that is an alias for an object. A local variable is an alias of an object when:
- It was declared as a Variable or Index parameter.
- It was assigned a Handle, such as:
Var X := HandleFromIdentifier("Va1");
Variable parameter won't accept a literal text, or a general expression, even if that expression returns a Handle. This is because the parameter is not actually evaluated as an expression would normally be as an actual parameter not qualified as an Index, Variable, or Object. For example, in
Fu2(X), X is the identifier of an object, it is not an expression that evaluates to an object. If the expression were evaluated, then
X would have to hold a varTerm. If you need to use an expression that evaluates to a varTerm, then you would define a local variable to contain the result of that expression and specify the local variable identifier when you call the function.
Within the Definition of the function, the parameter name
X serves as an alias for the original object, and can be passed to other functions that expect objects (i.e., Variable parameters), such as
WhatIf(y, X, x0), or
<attrib> Of X, or
X Of o if X is the name of an Attribute.
A Function called from a Script (not called from a Variable) can assign to the parameter,
X := <expr>, hence assigning a new definition to the variable
X refers to. In other contexts, if
X is in an expression or a parameter to another function that evaluates its parameters, Analytica evaluates
X to return its value.
If the object passed in as the parameter is a valid index, then
X can be used within the function in an index context, e.g.,
Sum(expr, X). The Index and Variable qualifiers differ in their behavior when the local variable is used in a value-context and a self-indexed table is passed in. In a value context, a Variable parameter will evaluate to the value, while an Index parameter evaluates to its index value.
The Variable qualifier is similar to pass-by-reference in other computer languages. When called from a script (with no caching variables involved), the underlying variable's Value, ProbValue, or other attributes, can be assigned to. (However, because of a prohibition on side-effects with dependency maintenance, you can't assign to the object when a function is called from a variable evaluation).
If the Variable Qualifier is followed by a Datatype qualifier, such as:
Fu3(X: Variable Number)
Analytica will evaluate
X when calling
Fu3 to check that its value has the specified Datatype. But, in the Definition of
Fu3, it will treat
X as an unevaluated Variable, as just above. The Coerce qualifier has no effect on a Variable parameter.
This qualifier is for internal use by built-in functions. It is a variation on the Variable qualifier.
A parameter with qualified as Object expects the identifier of any user-defined. This may be a Variable, Function, Module, or other class of Object. It is useful for meta-inference about Objects, for example to find the contents of a module. The Object is not evaluated -- which it could not be anyway if it was not a Variable.
The qualifier Handle is closely related to Object. The distinction is that Handle is a data type qualifier, while Object is an evaluation mode qualifier. If you have an expression that returns a handle when evaluated, and you want to pass the resulting handle to a function, then you would use the Handle qualifier. You would use the Object qualifier only if you want your function to accept an identifier directly without having to surround it within a call to the Handle function. Compare:
Fu1(obj: Object)--- call using:
Fu2(obj: Handle)--- call using:
new in Analytica 5.0 Specifies that a module is expected. The calling expression can be a module identifier, text containing the module identifier, or an expression that evaluates to a module identifier or to a textual module name. Can be used with or without the atom qualifier or other dimensional qualifiers.
Fu1(m : Module)
Fu1(m : Module atom)
Call using any of these:
new in Analytica 5.0
Specifies that an object Class is expected. This can be the identifier of a class, the textual name of a class, or a handle to the class object. To see a complete list of classes in Analytica, evaluate
#FindObjects(class:Object). Can be used with or without the atom qualifier or other dimensional qualifiers.
Call using any of these:
Specifies that a function expects a list of variables -- i.e., a list of pointers to Analytica objects. An example is the second parameter of built-in function WhatIfAll.
Related: List of Index
If you really want to pass a variable number of Variables as parameters to a function, it is better to use the ellipsis qualifier:
(vars: ... Variable)
In this case, it passes a list of handles to each variable to parameter vars, without evaluating them. Inside the function, vars contains a list of Handles.
When the VarList parameter is used, as with the declarations:
(vars: VarList[ ])
(vars: List[I] of Variable)
or with the related declaration:
(vars: List of IndexType)
Then the argument IS evaluated. The elements of the evaluated result must then be Handles. If not, an error results. In normal Analytica usage, it is pretty unusual for a result to evaluate to varTerms. If you use an identifier within an expression, it will evaluate to the underlying value, so it doesn't work to pass a list of identifiers. For example:
Function Fu1(vars: VarList)
Function Fu2(vars: ... Variable)
Fu1([Va1, Va2, Va3])-- won't work because the list expression [...] will evaluate the variables inside it.
Fu1(GetVariableByName(["Va1", "Va2"]))-- Good
Fu2([Va1, Va2, Va3])-- good
Fu2(Va1, Va2, Va3)-- good, equiv to previous
Fu2(GetVariableByName(["Va1","Va2"]))-- won't work
Evaluation Mode Qualifiers
Forces the parameter to be evaluated in Mid (deterministic) mode, irrespective of the context evaluation mode.
Forces the parameter to be evaluated in Prob (probabilistic) mode, independent of the context evaluation mode.
If your user-defined function applies statistical functions to a parameter, that parameter usually should be declared as Prob or Sample, otherwise your function may yield non-intuitive results. To illustrate, consider the following UDF that uses the statistical function Mean, shown two ways, with and without the Prob qualifier.
Function MeanMax1(X: Prob; J: Index) := Mean(Max(X, J))
Function MeanMax2(X: Array; J: Index) := Mean(Max(X, J))
Consider the results of applying these function in the following example:
Index Case := 1..3
Chance Damage := Table(Case)(LogNormal(10, 2), LogNormal(7, 3), LogNormal(12, 1.2))
Variable E_worst1 := Meanmax1(Damage, Case)
Variable E_worst2 := MeanMax2(Damage, Case)
E_worst2 may be evaluated in either Mid or Sample mode. Let's compare:
Expression Evaluation Context Mid Sample Mean(Max(Damage,"Case)) 20.53 20.53 MeanMax1(Damage, Case) 20.53 20.53 MeanMax2(Damage, Case) 12 20.53
From this table you can see that without the Prob qualifier, the result of
MeanMax2 in mid mode is not the same as
Mean(Max(Damage, Case). The potentially counter-intuitive result for
Mid(MeanMax2(Damage, Case)) occurs because the first parameter value is obtained by evaluating
Damage in mid mode, yielding the one-dimensional array
[10, 7, 12] indexed by
Case, rather than an array with the full distribution samples.
Like Prob, it forces the parameter to be evaluated in Prob mode, irrespective of the context mode. The only difference is that it gives an error message if the resulting value is not uncertain -- i.e. it does not contain the Run index.
Evaluates the parameter in Mid or Prob mode, according to the evaluation mode used to evaluate the function being called. Context is the default evaluation mode, if no qualifier (Mid, Prob, or Sample) is specified, so there is strictly no reason to use it.
Accepts any expression and does not evaluate it. It leaves it up to the function to evaluate it if needed. It is rarely used within user-defined functions, but is used in various built-in functions, for example:
Whatif(e: Unevaluated; v: Variable; x)
Causes the qualified parameter to be evaluated in Prob mode if any of the other parameters to the function are Run. If not, it evaluates in Context mode -- i.e. Prob or Mid following the context in which the function is called.
This qualifier is used for the main parameter of most built-in statistical functions. For example, Mean has these parameters:
Mean(x: ContextSample[i]; i: Index = Run)
Mean(X, Run) evaluates
X in Prob mode. So does
Mean(X), because the index
i defaults to Run. But,
Mean(X, J) evaluates
X in Mid mode, because
J is not Run.
When the parameter declaration contains more than one dimension, Prob mode is used if any of the indexes is Run.
Dimension qualifiers specify the dimensions -- that is, the indexes -- that the function expects for that parameter. The qualifier Atom specifies that the parameter value passed to the function must be a single value, with no indexes.
(x : Array[Time, I, J]) qualifies parameter x as having the three indexes listed. The main reason to use a Dimension qualifier is when the function will not work with parameters with different, usually more dimensions -- usually because it uses one of the Expressions that don't array-abstract. It is also of occasional use to conserve memory in a Function that may use a lot of memory temporarily during calculation. If it specifies few or no dimensions for its parameters, it is less likely to run out of memory during computation.
The key point to understand about dimension qualifiers is that they d not 'require that the actual value passed to the function has exactly those indexes and number of dimensions. Rather, they specify that the Function expects to work on a parameter with those indexes or number of dimensions. Analytica automatically resolves any mismatch between the dimensions of the actual value and the dimensional qualifier:
- If the actual value has more indexes than specified by the qualifier, it decomposes the value over the extra indexes into slices each with the expected indexes, and calls the function on each slice. It then reassembles the results from each function call into an array with those extra indexes. This reassembled result may also have additional indexes from the individual result of each function call, if that passes through indexes that it uses, or generates new indexes itself.
- If the actual value of a parameter is missing any expected index(es) specified in the dimensionality qualifier, the function also works fine. Any operation on a value
vover an index
vis not indexed by
vas constant over
i. For example, the atomic (scalar) number 4 is not indexed by
Time. Suppose time has 10 steps, so:
Size(Time) → 10.
Sum(4, Time) → 40
When multiple parameters have dimension qualifiers, Analytica coordinates the iteration over each parameter so that indexes impacting multiple parameters are iterated together.
(x : Array[Time, I, J]; I: Index; J: Optional Index)
The Array qualifier defines what indexes the parameter should have when passed to the Function. It consists of the word Array, followed by a list of one or more indexes in square brackets. Actually, the Array is optional, since the list of indexes in square brackets is sufficient. So, these two declarations are the same:
(x: Numeric Array[Time])
The Array qualifier specifies that the parameter is a multi-dimensional array (of zero or more dimensions), and is most importantly used to declare what those dimensions are. Inside the body of the function, parameter variable is guaranteed to contain no dimensions other than those declared. Analytica iterates over the function, calling it repeatedly on successive slices when an argument contains extra dimensions, so that this guarantee is satisifed within the function body -- this is the basis for Array Abstraction.
A is indexed by Time,
K1, K2, and
K3 and that a function having the above Typical Usage declaration is called as
F(A, K1). Analytica will iterate over all combinations of
A for each combination and calling
F each time with parameter
X indexed only by Time and
I (where parameter
I is an alias for
K1 inside the function Definition).
An array declaration does not add in dimensions, so for example, if in the earlier example, if the function were called using:
F(5, In1), inside the function body
X will be the scalar 5 -- the dimensions Time and
In1 are not automatically added to the parameter. However, since for all array-abstractable functions, 5 is equivalent to an array containing 5 for every element, computations will usually remain equivalent (and sometimes more efficient) even if the argument does not contain the dimension. The All keyword (described elsewhere on this page), used in conjunction with a dimensionality declaration.
When you define a function using procedural programming constructs, like While or or a local index with Sequence() that require their parameters to be Atoms, it is a good idea to qualify the dimensions of each function parameter that might affect them. The function will then array-abstract properly, and continue work if you add dimensions to the model later.
Specifies that the parameter is atomic -- a single element. If an array is passed to this parameter, Analytica will iterate over its dimensions so that at each call the parameter value is guaranteed to consist of a single element, typically a number, text string, a reference, or the value Null.
In esoteric cases, some internal data types can also be passed, which could theoretically include an parsed expression structure, a varset, a data blob (such as an image), a LP, QP or NLP problem-specification object.
Because an atom is considered to be a zero-dimensional array, the atomic qualifier is functionally equivalent to the Array qualifier with zero indexes, i.e.:
(X : Array[ ])
See also Atomic values and Atomic..Do.
The Scalar qualifier is an alias for "Number Atom".
(X: Vector[I]; I: Optional IndexType)
The vector qualifier specifies that the argument passed must contain at least one dimension, even if that dimension is not explicitly specified. When there is an explicit index provided, the behavior is the same as the Array qualifier. The distinguishing behavior occurs when no index is specified, such as when an optional index is omitted in the typical preceding typical usage. In such a case, array abstraction is applied to a vector parameter until a single dimension remains, while in the case of Array it would be applied until the parameter is scalar. When the parameter contains multiple dimensions, the default single remaining dimension will be the canonically first dimension. If no index can be identified, an error results.
Fu1 (X: Vector[I, J]; I, J: optional IndexType)
Fu2 (X: Array [I, J]; I, J: optional IndexType)
Fu3 (X : Vector)
Variable A := (indexed by In1 and In2)
X within function body:
Xis dimensioned by
In1. Iterates over
Xis atomic. Iterates over
Xis dimensioned by
In2. Iterates over
Fu1(A, In1, In2)=>
Xis dimensioned by
Xis dimensioned by
In1. Iterates over
Xis a null-indexed list of atoms. Iterates over
Xis atomic. Iterates over null-list,
Note that the example illustrate the difference between Vector and Array qualifiers.
Many built-in Analytica functions that operate on 1-D parameters act as if they are declared in this fashion (internally not all built-in functions use the newer parameter scheme documented here). These include Sum, Min, Max, Product, Cumulate, Uncumulate, CumProduct, etc.
(L: List[ ])
(L: List All [ ])
(L: List[I]; I: IndexType)
The List parameter qualifier is a variation of the Array qualifier that is used when a null-indexed dimension is expected, and the function does not want array abstraction it iterate over and remove that dimension before evaluating the function.
The array qualifier has no syntactic variation that allows you to the Null-dimension within the list of dimensions. The so-called Null-dimension does not really correspond to an actual Analytica object, but rather is a term that refers to a list. But, essentially, a declaration
List[I, J] would be the conceptual equivalent of
Array[NullDim, I, J]. It declares that the parameter may be indexed by the null-dimension,
J. Without the All qualifier, none of these dimensions are required, but they are the only ones allowed.
As is the case with the Array qualifier, a List declaration with no brackets is allowed but not particularly useful, since it doesn't restrict the dimensionality of the parameter.
(L : List[ ]) specifies that only the null-dimension is allowed. If the argument is not a list, then L will be atomic at each function invocation. If the argument has a null-dimension, then all other dimensions are iterated, with only the null-dimension passed to the function.
When the All qualifier is included, as in
(L: List All[I]) or
(L : List All[ ]), then both the specified index(es) and the null-index are required. When a null-index is added, Analytica has no reference index object to determine its length, so a null-list of length one is added.
When the list qualifier is used in conjunction with the Variable or Index qualifiers, a somewhat different treatment results. For these cases, see the VarList qualifier. "Variable List" or "List of Variable" is synonymous with VarList.
(A: Array All[I, J])
The All qualifier is used with Array, Vector, or List to specify that the function requires all listed indexes to be present. Without All, it allows, but does not require that the parameter has these dimensions. With All , the function body is guaranteed that the parameter has all and exactly the listed dimensions.
If an argument to an array parameter has extra indexes not listed, they are iterated, whether or not the All qualifier is present. If any named index(es) is (are) not an index of the actual parameter, it adds the index(es) as a dimension, repeating the value of the parameter across the added dimension(s). Internally, it represents them as sparse dimensions, so that there is little memory or time penalty involved in passing the extra dimensions; however, if the function operates over that dimension, intermediate or final results may require more memory, because for example, intermediate values may no longer be constant over those dimensions.
(A, B: Array[I]; C:Array[J]; D: Reduced)
When a parameter is declared with the Reduced keyword, it is sliced along any dimensions that are iterated as a result of dimensionality declarations on other parameters. For example, with the preceding declaration, suppose that the function is called with
A[I, J], B[I, K], C[J, K] and
D[I, J, K]. Then Analytica will iterate over
J (for parameter
A) and over
K (for parameters
D will thus be reduced by dimensions
K, so that within the function body,
D will be remain dimensioned only by
When a parameter is declared as Reduced, no index dimensions can be declared. In other words,
D : Reduced[I] would result in an error.
An example situation where the Reduced qualifier is useful is the following. Suppose a function can compute multiple related results. A parameter, computation, indicates which result is desired, e.g.:
Function Process(A: Numeric[I]; I: Index; computation: Reduced)
Within the function, Process can examine the computation parameter to determine exactly which computations need to be done. If the same computation is requested several times (for the same iteration along A), work does not need to be repeated, and if two computations share 90% of a computation, the function can leverage this fact, which it would not be able to do if these were done on separate iterations.
Data type qualifiers
A Data Type, such as Number, Positive Negative, Text, or Reference, is a qualifier to specify the expected type of value of a parameter. If the parameter doesn't have the specified type when the function is called, it gives an evaluation error. If the parameter is an array, it checks that every cell of the array is of the expected type. You can combine a Data type qualifier with an Array type qualifier, such as Vector, Array, or [I], or with object qualifier, such as Index. The qualifier Coerce requests that, if the parameter has a different type, Analytica should try to convert it to the desired type if possible -- e.g. convert a number to a text. The data type is optional. A small performance penalty is incurred at the time of a function call when the data type is specified.
Expects an expression that evaluates to a number (which includes INF, -INF, or NaN), or an array of numbers.
Expects an expression that evaluates to a text value (which includes empty text ), or an array of text values.
Expects an expression that evaluates to a Reference, or an array of references.
R must be a reference, or an array of references. Each reference may refer to any type of value or object without restriction.
A positive number, which could include INF, but not NaN.
Zero or a positive number, which could include INF, but not NaN.
Expects a handle to an object or an array of handles. These functions Handle, HandleFromIdentifier, IndexesOf return handles. You can also get a handle from the Contains or IsIn Attributes of an object, or an Array of Handles from the Inputs, Outputs, or Contains Attributes of an Object. Handles are used in Meta-Inference. The Handle qualifier is a different from the Variable, Index or Object qualifiers in that its parameter is typically evaluated. The Handle qualifier specifies the expected the data type, not the evaluation mode.
(new to Analytica 5.0)
A color can be either a color integer or a textual color name. A color integer is most conveniently written in hex notation as 0xaarrggbb or 0xrrggbb, where aa is the alpha value, rr the red value, gg the green value, and bb the blue value. For example,
0x80c0257d has an alpha of 0x80, a red of 0xc0, a green of 0x25 and a blue of 0x7d. A color name is a color name in English, such as 'Red', 'Yellow', 'Green', or 'Brown'. See Color parameters for a full list of color names.
If possible, it converts the value of the parameter into the desired type, Text or Number, as specified.
(t : Coerce Text; x: Coerce Number)
When coercing a number to Text, it uses the number format of the Variable or Function that calls the function which coerces its parameter(s)-- not the number format of the called function.
Function Result_text(x: Coerce Text) := 'The result is ' & x
Variable Y := Result_text(12345.678)
Y uses Analytica's default Number Format, which is suffix format with 4 significant digits, it gives
Y -> 'The result is 12.35K'
But if the Number format of Y was set to Fixed point with 2 decimal digits and commas, it gives
Y → 'The result is 12,345.68'
When coercing from Text to Number, it tries to parse text containing numbers using the number format.
Coercion to a reference returns a reference to an atomic value (text or number) that is not already a reference. Coercing an array to a reference returns an array of references to the elements of the array.
In all cases, if a coercion is not possible (including when a text does not contain a valid number), it flags an evaluation error.
(A : Ascending[I])
(L : Ascending List[ ])
(I : Ascending IndexType)
The ascending qualifier specifies that the values of a list, vector, array, or index must be in non-strictly ascending order. Use of this qualifier requires that the declaration specifies a one-dimensional parameter. Without one dimension, the index over which it must be ascending is ambiguous, and hence an error is issued.
The test triggers an error if any element is less than the value that precedes it. The test is non-strict, so that a constant array, or an element equal to its predecessor, does not trigger an error. There is no parameter qualifier variation that tests for strict ascending order.
The descending qualifier specifies that the values of a list, vector, array, or index must be in non-strictly descending order. It is the exact dual of the Ascending parameter qualifier -- see the description above for Ascending for details.
Optional and repeated parameters
Function F1(x: optional)
Function F2(a: Array[I]; i: optional IndexType)
Function F3(a: Optional = 0; b := 99)
The Optional qualifier specifies that a parameter is optional. If the function is called with no value, the parameter has the value Undefined inside the function. You can test if the value is undefined with functions IsNotSpecified(...) or IsUndef(...).
You can provide a different default using an equal sign, as in the example,
a: = 0 for
F3 above. In that case, the parameter gets the specified default if none is provided when you call it.
The function, you can pass a parameter declared as optional as a argument to another function having an optional parameter. If the parameter is not specified to the first function, it will appear to the second function as if it is not specified as well. Within the body, should the parameter variable itself be used, it contains the special system value Undefined.
Optional can be applied to values or indexes. Using the optional qualifier on index parameters causes array parameters using that index to be of variable dimensionality.
Note: Use of the ellipsis qualifier, or the inclusion of a default value, are alternative means to specify optional or variable-length parameter lists.
ident: qualifiers = defaultValue
(X: Optional Number = 0)
(X: Number = 0)
(A: ContextSample[R]; R: Index = Run)
You can specify a default value to be used for an optional parameter when the parameter is omitted when calling the function. In the parameters, you simply include
= <defaultVal> in the qualifier. If you specify a default in this way, you don't need to include the "Optional" qualifier since it is implied. For a value parameter, the optional value should usually be a literal, a number or text. You may use an expression, but we don't recommend it. For an Index or Variable parameter, the optional value must identify an index or variable. For one of these Unevaluated parameter types, the default could be another parameter of that type declared earlier in the parameters list.
For an index parameter you may specify the default as code>Common, meaning that the default the index common to all array parameters using that index. For example:
(P, R: Array[I]; I: Index = Common)
In this case, the parameters passed for
R must share exactly one index if
I is not specified.
Repeated parameters (...)
(X: ... Scalar)
(A: Array[I] ; I : ... IndexType)
You qualify a parameter as repeated with three dots "..." or the keyword
Repeated: The function accepts one or more actual parameters of the given type. If you combine "..." with Optional, it accepts zero or more parameters -- instead of requiring at least one parameter. In the Definition of the function, a repeated parameter is a list (with Null index) containing the actual parameters given. For example,
Function ValMax(x: ... Number) := Max(X)
ValMax(3, 6,-2, 4) → 6
ValMax() returns the maximum value of its repeated parameter. Unlike the built-in Max function, it doesn't need square brackets around its parameters. During evaluation of
X is the null-indexed list
[3, 6,- 2, 4].
ValMax could also be applied to array arguments, such as
ValMax(Sqrt(X), X^2, 0)
Function Total(a: Array[I]; i: ... IndexType)
sums its parameter, a, over one or more specified dimensions -- a generalization of Sum(A, I). For example:
Total(A, I, J, K)
It is equivalent to:
Sum(Sum(Sum(A, I), J), K)
(Actually, the built-in Function Sum, and other array-reducing functions, including Product, Min, Max, Average, already let you provide a list of indexes to work over.)
Inside the body of
A would be an array containing the Null-index, along with all dimensions listed in the
You can specify an array parameter with a variable number of explicit indexes, by using the ellipsis on an index parameter, e.g:
(A: Array[I]; I: ... Optional IndexType)
A parameter passed to an repeated parameter may NOT be indexed by Null. (However, you can use brackets to group a variable number of arguments in the call, see examples below).
Iterating over repeated parameters
When a User-Defined Function has a repeated parameter, for example when its Parameters are:
( x : ... )
(x : repeated)
the best way to iterate over the supplied parameters in the Definition of the UDF is:
FOR xi := Repeated x;
Repeated keyword means that the local will get each parameter from repeated parameter x successively. For example, if you call this function as
F(a, b, c)
c each have different dimensions,
xi will alias each of these values in turn. A couple syntactic variations are to use Local in place of For, or you can include parens around the name, e.g.,
For xi := repeated(x) Do ...
You can also access these using, e.g., Slice(x, 2) for the second repeated. It is best, however, not to treat the repeated "dimension" as you would the implicit dimension, otherwise you may end up with the union of the incoming dimensions.
Calling a function with repeated parameters
Several syntaxes may be used when calling a function containing an repeated parameter. When the parameter is named in the call, then all arguments that follow are considered to be instances of that parameter up until another parameter name is indicated. For example, in the declaration You may use several methods to specify the actual parameters to a function with repeated parameters. For this function:
Function Fxy(X: ... scalar; Y: ... Optional Scalar)
you may give the repeated parameter by name:
Fxy(X: 1, 2, 3, 4, Y: 5, 6, 7)
Use position and naming only the second parameter Y:
Fxy(1, 2, 3, 4, Y: 5, 6, 7)
In this case, the first four are treated as parameters to X. You needed to specify parameter Y by name, to make clear that the second four are elements of Y.
You may also use square brackets with pure positional syntax:
Fxy([1, 2, 3, 4], [5, 6, 7])
The brackets prevent ambiguity.
Repeated parameters for indexes are useful to enable a variable number of dimensions for an array parameter. However, you cannot (currently) use the individual indexes explicitly from within the user-defined function.
Note that Repeated indexes can be mixed with non-Repeated indexes in array declarations, e.g.
(A: Array[I, J]; I: IndexType; J: ... IndexType)
This function requires two or more indexes:
I and one or more instances of
Using Index with Optional and Repeated Qualifiers
I: Index-- The function requires an index parameter
I: Optional Index-- the function can accept an Index parameter, but it is optional.
I: Index = J-- the function can accept an Index parameter. If omitted it defaults to
=to specify a default value implies the parameter is optional, even if the keyword
I: Index = Run-- the function can accept an Index parameter. If omitted it defaults to Run].
I: Repeated Index-- the function expects a list of one or more Index parameters.
I: ... Optional Index-- the function expects a list of zero or more Index parameters. Ellipsis "..." is a synonym for
You can also use a local variable that refers to an Index:
VAR v := GetVariableByName("In1") DO Fu1(v)
which is equivalent to
You cannot specify a general expression where an Index is required, so you could not compose the above to:
When marked as hidden, a parameter does not appear in the object finder dialog, or when pasting the definition via the definition menu. The parameter, however, is there and can be specified in a function call.
Internally Analytica makes use of hidden parameters in the following construct:
(A; exprA: hidden unevaluated = A)
This allows the underlying implementation access to the expression for
A, while still receiving the evaluated parameter
A (suitably iterated and typechecked if other qualifiers are attached to
The Of qualifier is ignored by the parameter qualifier parser, but can be included within qualifier list for stylistic preference, such as:
(X : Ascending Array[I, J] of Number)
(L : List of Number)
as equivalent alternatives to
(X : Ascending Number Array[I,J])
(X : Number List)
and so on. Note that qualifiers can appear in any order, and contain various aliases (such as Numeric or Numbers) to make either stylistic variation sensible, depending on user preference.
Deprecated Synonyms for Parameter Qualifiers
We originally defined synonyms for some parameter qualifiers, thinking it would let you specify parameter lists more flexibly. In practice, users found it harder to recognize and remember so many terms, so we have chosen one preferred term for each qualifier and deprecate the others -- i.e. we advise you not to use them. Please use the preferred terms, since the deprecated ones may not be supported in future releases.
For the benefit of those looking at old Analytica code, here are the synonyms, after the recommended term for each qualifier:
Recommended term Synonyms
Probabilistic, ProbType, Uncertain
Samp, SampType, SampleType
Determ, DetermType, DetermMode, MidMode
ContextSamp, MaybeSamp, MaybeSample
VariableType, Var, VarType
VarList, Variable List, List of Variable
Atomic, AtomicType, AtomType
Numeric, Numbers, NumberType, NumericType, Num, Real, Boolean
Textual, TexType, TextType
Ref, RefType, ReferenceType
Enable comment auto-refresher