Next: syntaxes operations, Previous: syntaxes variables, Up: syntaxes [Contents][Index]
An overloaded function represents an aggregation of functions linked to the same name and having different number and/or type of arguments. For example, in the code:
(define/overload (fun {O <fixnum>}) (list 'fixnum O)) (define/overload (fun {O <string>}) (list 'string O)) (define/overload (fun {A <vector>} {B <vector>}) (list 'vectors (vector-append A B))) (fun 123) ⇒ (fixnum 123) (fun "ciao") ⇒ (string "ciao") (fun '#(1) '#(2)) ⇒ (vectors #(1 2))
an overloaded function named fun
is defined by the first use of
define/overload
; subsequent uses add new specialisations to the
same function.
In the above example: the selection of the specialised function happens at expand–time, because the expander can determine the type of the operands. Early binding (more precisely: expand–time dispatching) is available only with the “canonical” function application syntax:
(?fun ?operand ...)
Here is an example of late binding (more precisely: run–time dispatching, or dynamic dispatching):
(define/overload (doit {O <string>}) (list 'string O)) (define/overload (doit {O <fixnum>}) (list 'fixnum O)) (map doit '("ciao" 123)) ⇒ ((string "ciao") (fixnum 123))
putting the overloaded function’s syntactic identifier in reference position will reference a special function that implements dynamic dispatching.
It is an error to define two specialised functions with the same formals type signature. Specialised functions are allowed to have different type signatures for the returned values, but we should use this feature with care; it is suggested not to abuse overloaded functions by adding specialised functions that perform unrelated operations.
We can overload functions only in the same lexical context, the following code will create two functions:
(define/overload (fun {O <fixnum>}) ---) (internal-body (define/overload (fun {O <string>}) ---) ---)
We can define an overloaded function in a library and then add specialised functions in a second library which depends on the first one.
Whenever an overloaded function is applied to a tuple of operands: first expand–time early binding is attempted; if it fails, run–time late binding is attempted. At expand–time:
&warning
exception is raised signalling failure in
early binding.
At run–time:
type-descriptor-of
,
type-descriptor-of.
&overloaded-function-late-binding-error
, (vicare-scheme)Overloaded function late binding
conditions.
Specialised functions are ranked to select the better matching. At both expand–time and run–time, ranking works by iterating a list of specialised functions:
Here is an example that shows how ranking works:
(define/overload (fun {O <number>}) `(number ,O)) (define/overload (fun {O <real>}) `(real ,O)) (define/overload (fun {O <fixnum>}) `(fixnum ,O)) (fun 1+2i) ⇒ (number 1+2i) (fun 3.4) ⇒ (real 3.4) (fun 5) ⇒ (fixnum 5)
notice that, at expand–time, only the operands’ type signature seen by the expander is the one that matters, with the same definitions above:
(fun (cast-signature (<number>) 123)) ⇒ (number 123) (fun (cast-signature (<real>) 123)) ⇒ (real 123) (fun (cast-signature (<fixnum>) 123)) ⇒ (fixnum 123)
The following syntactic bindings are exported by the library
(vicare)
.
Define a specialisation for the overloaded function ?who. If this is the first specialisation for ?who, also define the overloaded function; otherwise define only the specialisation and register it in the already existent ?who.
The syntax has the same format of define/typed
, it defines a
function with type annotations for both the arguments and the return
values. The function’s type signature is used only at expand–time to
validate the type of the operands used in an application.
Next: syntaxes operations, Previous: syntaxes variables, Up: syntaxes [Contents][Index]