[Next] [Previous] [Up] [Top] [Contents] [Index]

6 Functions

Parameter Lists

The parameter list of a function describes the number and types of the arguments which the function accepts, and the number and types of the values it returns.

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.

Kinds of Parameters

Dylan parameter lists support required parameters, rest parameters, keyword parameters, and sometimes a next-method parameter. They also may include return type declarations.

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.

Kinds of Parameter Lists

Each function (generic function or method) has an argument passing protocol specified by its parameter list. The argument passing protocol for a method must be compatible with the argument passing protocol of any generic function to which it is added, as described in "Parameter List Congruency" on page 91.

The argument passing protocol of a function can be described in one of the following ways:

Specializing Required Parameters

When you define a generic function or method, you may specify the types of the arguments appropriate for the generic function or method. This is called specializing the generic function or method, or specializing the parameters of the generic function or method.

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:

Keyword Parameters

The syntax of a keyword parameter is:

[ 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);

Types for Keyword Parameters

When a type is indicated for a keyword parameter in a method, it is the same as establishing a type for a local binding. Specifically, the types of any keyword parameters are not used for method dispatch. Keyword parameter types are not allowed in generic function definitions, and do not figure into parameter list congruency.

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>
= lookup-default-restaurant())
...
end method find-food;

Result Values

Parameter lists may include value declarations. Value declarations come at the end of the parameter list and are separated from the parameters by =>. 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:

define method average (x :: <number>, y :: <number>)
 => mean :: <number>;
 (x + y) / 2
end method;
// 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;
Note that the following example does not declare a return value of type <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;

Parameter List Congruency

For any given generic function, the generic function and all methods for that function must have congruent parameter lists. Two parameter lists are congruent if they satisfy the following conditions:

Parameter Lists of Implicitly Defined Generic Functions

As a general principle, the parameter list of an implicitly defined generic function will impose as few constraints as possible on the methods that may be added. If a more constrained generic function definition is desired, an explicit definition should be used.

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.


[3] In practice, an implementation may place a reasonable limit on the number of arguments that may be passed to any function.
Dylan Reference Manual - 17 OCT 1995
[Next] [Previous] [Up] [Top] [Contents] [Index]

Generated with Harlequin WebMaker