Re: Variadic functions and dynamic function calls

On Thu, 10 Dec 2020 at 13:06, Michael Kay <> wrote:

> My thinking is that the last argument to an array-variadic function is
> either an array, or the item-type it is an array over. That is, a function
> reference name#arity where arity is the number of parameters in the
> array-variadic function is a union-of(array(T), T). For function matching
> rules, this would mean that the last parameter can either be an array(T) or
> T.
> The problem is, it can be both. For example if T = array(*), and you
> supply `[[]]` then the supplied argument satisfies both array(T) and T. So
> we can't use the dynamic type of the argument to resolve the ambiguity.

I have thought about this a bit more, and agree with your line of reasoning
w.r.t. using sequence-variadic functions for this style of variadic
function instead of array-variadic functions, due to what you mention about
(T) and T being equivalent for sequences, but the analogous array version
not being equivalent.

My reasoning for keeping array-variadic functions was to permit things like
an array constructor function, or similar construct where sequence
flattening is undesirable. I'm now wondering if it makes more sense to have
a way of programatically accessing the arguments as an array, like is done
in languages like JavaScript. That is, defining a new function:

    fn:function-arguments($from as xs:integer := 1, $to as xs:integer? :=
()) as array(*)
    (: This function is ·deterministic·, ·context-dependent·, and
·focus-independent·. :)

that returns an array of the arguments passed to the function, or raises an
XPST error if the context is not a function. If to is an empty sequence, to
will be equivalent to the arity of the function call. Note that for a
map-variadic function, this would return the arguments without their
corresponding keywords in the order they were passed to the function.

That function would allow for the use case where an array, or the
unflattened arguments are needed. The function could make use of the new
"for member ..." syntax if it wanted to process the arguments separately.

This means you could define an array constructor function as something like:

    declare function fn:array($members as item()*...) as array(*) {

Note that this function -- and other functions like MarkLogic's
sem:coalesce -- is an example where each parameter can be a sequence (e.g.
item()* in both this example and xdmp:apply). The fn:concat function is an
example where the parameters are an optional item (i.e. xs:anyAtomicType?).
In other functions like BaseX's perm:allow, the variadic type is an item
type (so empty sequences are not allowed as arguments).

This means that argument type checking should be against the sequence type
that is declared as variadic at the point at which the function is being
called, and the sequence construction should be done once the validation
has been completed and the arguments are passed to the function.

Kind regards,

> Michael Kay
> Saxonica

Received on Thursday, 10 December 2020 17:59:33 UTC