Argument Processing
•
|
Argument processing occurs when a function call results in the invocation of a procedure. First, all the arguments are evaluated (except those corresponding to parameters with the evaln or uneval modifiers), and then they are matched to the parameters of the procedure.
|
|
Keyword Matching
|
|
•
|
Keyword arguments are always matched first unless the procedure has parameters declared with the uneval or evaln modifiers. Maple makes a pass through the entire sequence of arguments looking for keyword=value equations where the keyword matches a declared keyword parameter of the procedure.
|
•
|
Whenever a matching keyword parameter is encountered, the right-hand side of the equation becomes the value for that parameter, and the equation is removed from further consideration as an argument. If more than one keyword argument matches a keyword parameter, only the last one takes effect.
|
•
|
Keyword parameter names (the keyword part) are Maple symbols like any other. If that symbol is in use as a variable, then using it in a keyword argument may not work as expected, since the variable may evaluate. To ensure that this does not happen, it's best to always use unevaluation quotes around the keyword part of a keyword argument:
|
>
|
f := proc( x::integer, { y::integer := 1 }, $ ) x * y end:
|
| (1) |
•
|
When calling a procedure that accepts a keyword argument from within another procedure that has a parameter with the same name as the keyword argument, it is necessary to use both unevaluation quotes and the scope resolution operator, :-, to ensure that the global keyword is used instead of the value of the parameter:
|
>
|
f := proc( x::integer, { y::integer := 1 }, $ ) x * y end:
|
>
|
g := proc( y::rational )
f(numer(y), ':-y'=denom(y))
end:
|
| (2) |
|
The Implied true Value
|
|
•
|
If a keyword parameter has a declared parameterType for which true is a valid value (for example, the types truefalse or boolean), the keyword name alone may be used as an argument. In that case, keyword is a short form for keyword=true.
|
>
|
f := proc( x::integer, { square::truefalse := false } )
if square then
x^2
else
x
end if
end proc:
|
| (3) |
| (4) |
| (5) |
|
|
Indexed Keyword Arguments
|
|
•
|
If a keyword parameter's keyword is of the form `symbol[symbol]` or `symbol[integer]`, the parameter is treated specially at argument processing time. Although such a keyword is still just a symbol (because of the surrounding left single quotes), it matches indexed names.
|
•
|
Specifically, if an equation whose left-hand side is an indexed name of the form `symbol[symbol]` or `symbol[integer]` is encountered, it matches the keyword parameter whose keyword symbol looks like the indexed name. For example, the argument,
|
|
matches this keyword parameter:
|
|
{ ... `axis_label[1]`::string := "x" ... }
|
•
|
Keyword arguments with multiple indices are also recognized, by attempting to match them using one index at a time. For example, the argument,
|
|
matches both of these keyword parameters,
|
|
{ ... `axis_label[1]`::string := "x", `axis_label[2]`::string := "y" ... }
|
|
setting them both to the empty string.
|
>
|
f := proc( { `name[1]`::string := "hello",
`name[2]`::string := "goodbye" } )
sprintf("name[1]=\"%s\" name[2]=\"%s\"",
`name[1]`,`name[2]`)
end proc:
|
| (6) |
>
|
f(name[1]="bonjour",name[2]="aurevoir");
|
| (7) |
>
|
f(name[1,2]="good day");
|
| (8) |
|
|
The evaln and uneval Special Case
|
|
•
|
There is one case where keyword matching as described so far is not done first. Only if the procedure was declared with any parameter(s) having an evaln or uneval modifier, arguments are first assigned to positional parameters left to right until the rightmost evaln or uneval parameter has received an argument or until all the arguments have been exhausted, whichever happens first. For each argument/parameter pair:
|
–
|
If the parameter has no type declaration, the argument matches trivially, and becomes the value for that parameter.
|
–
|
If the parameter has a type declaration, the argument may or may not match. If it matches, the argument becomes the value for that parameter. If it does not match, an exception is raised. For example:
|
|
Error, invalid input: f expects its 1st argument, x, to be of type integer, but received 2.3
|
•
|
The following example illustrates this special case behavior:
|
>
|
accumulate := proc( r::evaln(numeric), n::numeric,
{ operation::symbol := `+` } )
r := operation(eval(r), n)
end proc:
|
| (9) |
| (10) |
>
|
accumulate(total,operation=`*`,10);
|
| (11) |
>
|
accumulate(operation=`*`,total,100);
|
|
|
|
Positional and Ordered Parameter Matching
|
|
•
|
After all arguments matching keyword parameters have been processed, matching of required positional and optional or expected ordered parameters is carried out. If any parameter had an evaln or uneval modifier, all parameters up to the rightmost of these will already have received arguments, so further matching begins with the next positional or ordered parameter after that.
|
•
|
Matching is done by traversing the parameter declarations from left to right. As each parameter is examined, an attempt is made to match it to the next unused argument as follows:
|
|
1. If the parameter has no type declaration, the argument matches trivially, and becomes the value for that parameter.
|
|
2. If the parameter has a type declaration, but no default value, the argument may or may not match. If it matches, the argument becomes the value for that parameter. If it does not match, an exception is raised. For example:
|
|
Error, invalid input: f expects its 1st argument, x, to be of type integer, but received 2.3
|
|
3. If the parameter has a type declaration and a default value, the argument may or may not match. If it matches, the argument becomes the value for that parameter. If it does not match, the parameter receives its default value, and the argument remains available for matching a subsequent parameter.
|
•
|
In cases 2 and 3 above, if the parameter's type uses the seq modifier, Maple continues to match additional arguments against the parameter until one is encountered that is not of the right type. A seq parameter never results in an exception, because even if no arguments match, a valid sequence has been produced (the empty sequence).
|
•
|
At the end of this process, if there are any arguments left over, they are either put into the _rest sequence, or, if the procedure was declared with the end-of-parameters marker, $, an exception is raised:
|
|
Error, invalid input: 2 positional arguments passed to f but only 1 positional parameter specified; first unused argument is a^2+b
|
•
|
If on the other hand all the arguments were used up, but there are parameters remaining to be assigned values, these receive their default values if they have one. Otherwise, they have no value, and attempting to use them within the procedure raises an exception.
|
•
|
Note: The actual order in which some of these actions occur is slightly more complicated than described. Specifically, when an argument is assigned to a typed positional parameter (i.e. one with no default value), the type check is not carried out until argument processing is completed, since the type may depend on the value of a later parameter.
|
>
|
f := proc( x, y::integer, z::string := "hello" )
x, y, z, [_rest]
end proc:
|
| (12) |
| (13) |
| (14) |
| (15) |
|
|
Details
|
|
|
For further information on parameters, see
|
|
|