6 Functions
The parameter list of a generic function is used to define the overall protocol of the generic function. It constrains the methods that may be added to the generic function, through the parameter list congruency rules described on page 91. It may also specify that calls to the generic function may contain any keyword arguments.
The parameter list of a method specifies the types of arguments to which the method is applicable, and declares local bindings to which those arguments will be bound during the execution of the body of the method. It may also declare the return value types of the method.
The complete syntax of parameter lists is given in "Methods" on page 410.
Required parameters correspond to arguments which must be supplied when a function is called. The arguments are supplied in a fixed order and must appear before any other arguments.
Each required parameter may be a name or a name specialized by a type. Specifying a type declares that supplied argument must be a general instance of that type.
A rest parameter allows a function to accept an unlimited number of arguments.[3] After the required arguments of a function have been supplied, any additional arguments are collected in a sequence, which is passed as the value of the rest parameter. This sequence may be immutable, and it may or may not be freshly allocated. The types of rest parameters cannot be declared.
Keyword parameters correspond to arguments that are optional and may be given in any order. Symbols are used among the arguments to guide matching of arguments to parameters. These symbols are usually written in keyword syntax and so they are known as keywords. Keyword arguments can only be supplied after all required arguments are supplied. Keyword parameters may be specialized, restricting which values may be supplied for them. Keyword parameters may also be given default values to be used when the caller does not supply a value.
Required parameters come first in the parameter list, followed by the rest parameter, if any, and then the keyword parameters, if any. A rest parameter is indicated by the token #rest followed by the name of the parameter. Keyword parameters are indicated by the token #key followed by the keyword parameter specifiers, optionally followed by the token #all-keys.
If #rest and #key are used in the same parameter list, #rest must come first. The rest parameter will be bound to a sequence containing all the keyword arguments and their corresponding values.
A next-method parameter is indicated by the token #next, followed by the name of the parameter. It is not normally necessary to specify a next-method parameter explicitly. If a next-method parameter is not specified by the programmer, define method inserts one with the name next-method. If an explicit next-method parameter is given, it must come after the required parameters and before the rest and keyword parameters. Details of using next-method are given in "Calling Less Specific Methods" on page 96.
The argument passing protocol of a function can be described in one of the following ways:
#key
.
#key
in addition to #rest
it is not said to accept a variable number of arguments.)
A method that accepts keyword arguments is said to recognize the keywords mentioned in its parameter list. (A method may, of course, mention them in the parameter list and then ignore their values. It is still said to recognize them.) It is possible for a method to accept keyword arguments in general but not recognize any particular keywords; it does this by specifying #key
without any subsequent keyword parameters.
If a generic function that accepts keyword arguments mentions any specific keyword arguments in its parameter list, these are the mandatory keywords of the generic function. Every method added to the generic function must recognize these keywords.
A function may accept all keyword arguments by specifying #all-keys
in its parameter list.
When a function that accepts keyword arguments is called, it is said to permit a keyword argument in the call if one of the following is true
If a function that accepts keyword arguments is called, it will signal an error if called with a keyword argument that it does not permit, or if the arguments following the required arguments are not keyword/value pairs. This is true even if the function specifies #rest
.
If a method is called via a generic function or via next-method (rather than directly), the method itself does not check whether it received any keyword arguments it does not permit, nor does it check that the arguments following the required arguments are keyword/value pairs. This check is performed by the generic function or next-method, and is made relative to the call as a whole, not relative to an individual method or the methods remaining to be called.
A call to a function may supply the same keyword argument more than once. When this is done, the leftmost keyword/value pair is used.
The following example defines a method specialized on <number>
. The method will be applicable when double is called on a general instance of <number>.
define method double (thing :: <number>) thing + thing; end method;Specialization constrains the values that may be passed as the value of a parameter. The function can be called only with arguments that are instances of the specializers of the corresponding parameters.
Specialization is useful in three way:
Syntactically, specializers are operands. These operands are executed once when the function is created. They are not re-executed each time the function is called. The value of the operand must be a type.
It is most common for specializers to be constant module bindings or calls to a built-in type constructor such as singleton
, limited
, or union
.
There is a convenient syntax for singleton specializers, which is equivalent to explicitly calling singleton
in the current lexical scope.
[ keyword ] name [ :: operand ] [ = expression ]
If keyword is not supplied, then name is used to indicate both the keyword and the name of the parameter. If the keyword and name are given independently, the keyword is used when calling the method, and the name is used as the name of the parameter inside the body of the method.
The expression supplies a default value for the parameter. It is used when the method is called and the keyword is not supplied. It is executed each time the method is called and the corresponding keyword argument is not supplied. If no expression is specified, the parameter corresponding to an unsupplied keyword argument is initialized to #f
. The expression is executed in a scope that includes all the preceding parameters, including required parameters, the rest parameter (if any), the preceding keyword parameters, and the next-method parameter (if any).
In the following example, all three keyword parameters have default values, and all three use the same name for the keyword and the parameter.
define method percolate (#key brand = #"maxwell-house", cups = 4, strength = #"strong") make-coffee (brand, cups, strength); end method;The caller can choose which keyword arguments to supply and what order to supply them in:
percolate (brand: #"java", cups: 10);
percolate (strength: #"strong",
brand: #"starbucks",
cups: 1);
The following method has two keyword parameters. In each, the name of the keyword and the name of the parameter is specified separately. The first keyword parameter has a default value, the second does not.
define method layout (widget, #key position: the-pos = 0, size: the-size) let the-sibling = sibling (widget); unless (the-pos = position (the-sibling)) align-objects (widget, the-sibling, the-pos, the-size); end method; layout(my-widget, position: 100, size: 500); layout(my-widget, size: query-user-for-size() );The keyword parameter syntax in which the keyword name and parameter name are given separately is needed to allow keyword names such as
position:
without forcing the method to use position
as a local binding. If a method uses position
as a local binding, it cannot access the module binding position
(which contains a function). The local binding would shadow the module binding.
All required arguments must be supplied before any keyword arguments can be supplied. The following call to layout
will signal an error:
layout(position: 100, size: 500);
The following two method definitions are equivalent:
method (#key X :: <integer>) ... X ... end method; method (#key X) let X :: <integer> = X; ... X ... end method;If a keyword parameter is given a type, if
#f
is not an instance of that type, and if they keyword parameter is not given a default value, then the keyword parameter is essentially required. An error of type <type-error>
will be signaled if a call to the method does not include the keyword.The following examples include keyword parameters that include both a type and a default value.
define method find-happiness (#key hint :: <symbol> = #"here") ... end method find-happiness;define method find-food (#key hint :: <restaurant>
=>
. For each return value, a value declaration can specify a name and an operand or just a name if the type is <object>
. The complete syntax of value declarations is given in "Methods" on page 410.The result of executing the operand at the time the function is defined is a type, called a value type. The name never comes into scope. It is included for documentation and for syntactic consistency with parameters. It is valid for the same name to be used in both one parameter and one value declaration in the same parameter list; this is useful as documentation that a function returns one of its arguments.
The last value declaration can be preceded by #rest
to indicate a variable number of return values. A value declaration preceded by #rest
is called a rest value declaration. A value declaration not preceded by #rest
is called a required value declaration. The value type in a rest value declaration is the type of each one of the remaining individual values, not the type of a conceptual sequence of multiple values.
If a parameter-list does not contain a value declaration, it defaults to => #rest x :: <object>
. That is, the function can return any number of values of any type.
A function will always return the number and types of values declared in its parameter-list. More precisely:
Because of the parameter list congruency rules for result value declarations, the values returned by a generic function do not have to be checked by the generic function. The check inside a method will always be enough to verify that the return values are valid for the generic function.
define method average (x :: <number>, y :: <number>) => mean :: <number>; (x + y) / 2 end method;Note that the following example does not declare a return value of type// Returning multiple values define method limits (center :: <number>, radius :: <number>) => (min :: <number>, max :: <number>); values(center - radius, center + radius); end method;
// The same name used both as a parameter and as a value type define method rotate (image :: <picture>) => (image :: <picture>, rotation-angle :: <number>); ... end method;
// This method can return one, two, or three values define method family (kid :: <person>) => (kid :: <person>, #rest parents); let mom = kid.mother; let dad = kid.father; case mom & dad => values(kid, mom, dad); mom => values(kid, mom); dad => values(kid, dad); otherwise => kid; end case end method family;
<number>
. It declares a return value of type <object>
. To specify a type, both the name and the type must be specified. If only one is given, it is taken as the name.
define method average (x :: <number>, y :: <number>) => <number>; (x + y) / 2 end method;
In addition, the value declarations must be congruent, defined as follows:
The parameter list of an implicitly defined generic function is determined by its method definitions. These method definitions include both methods defined using define method
and slot getter and setter methods defined using define class
.
<object>
.
<object>
.
Generated with Harlequin WebMaker