From 34c43835b2fb4718be958394f061f2e14b0e06f5 Mon Sep 17 00:00:00 2001 From: Reece Dunn Date: Mon, 15 Oct 2018 13:08:32 +0100 Subject: [PATCH 1/7] Variadic Function Arguments --- variadic-function-arguments.md | 76 ++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 variadic-function-arguments.md diff --git a/variadic-function-arguments.md b/variadic-function-arguments.md new file mode 100644 index 0000000..2cf1402 --- /dev/null +++ b/variadic-function-arguments.md @@ -0,0 +1,76 @@ +# Variadic Function Arguments + +**Author**: Reece H. Dunn. 67 Bricks. + +Allow support for a variable-length sequence of typed parameters to a function. + + +## Description + +A variadic function parameter has at least 1 item. The upper bound is unbounded, but may be an implementation defined limit. + +For a function with `N` non-variadic parameters and a variadic parameter, that function defines a set of functions in the static context with the specified function name, and arity of `N+1` upward to the maximum number of arguments supported by an implementation. + +A function reference to a variadic function will behave the same as if the function was defined with the specified arity, or an error if there are fewer arguments than the requested arity. + +If the function reference specifies an arity equal to one more than the number of non-variadic arguments (i.e. where the variadic size is 1), the last argument is treated as having a type equal to the union of the specified type and an array of the specified type. + +When a function with variadic arguments is called, the arguments after the argument that corresponds with the last non-variadic parameter are collected into an array in the same order and passed to the variadic parameter. + +A function with a variadic argument may be passed an array or sequence to that argument. If it is passed a sequence, the sequence is treated as if it was wrapped in an array constructor. + +### Influences + +There are many languages that have support for variadic function arguments, including C/C++ and Java. Java supports variadic parameters by mapping them to an object array. + + +## Use Cases + +Define the `fn:concat` function in the XPath and XQuery Functions and Operators 3.1 specification using valid XPath/XQuery syntax, instead of hand-waiving the variadic nature of the function. + +Support other vendor-specific functions that allow variadic arguments. + +Support user-defined functions like sum or product that take a variable number of arguments without requiring nested parenthesis (e.g. using `sum(1, 2, 3)` instead of `sum((1, 2, 3))`). + +### Requirements + +1. MUST be backward compatible with XPath 3.1 and XQuery 3.1. + +1. MUST limit the variadic function syntax to the last parameter of an inline function (XPath/XQuery), or named function declaration. + +1. MUST make use of arrays or similar functionality to preserve the position of empty sequences in function calls. + +1. MUST support named function references (XPath/XQuery) to the function with any arity above the number of defined arguments. + +1. MUST support defining `fn:concat` using the variadic function parameter syntax. + +1. MUST allow access to the variadic arguments within the function body of an XPath/XQuery expression or function declaration. + +1. MAY allow passing arrays or sequences as the variadic parameter instead of passing separate arguments. + +## Examples + +### fn:concat + + declare function fn:concat( + $arg1 as xs:anyAtomicType?, + $args as variadic array(xs:anyAtomicType?) + ) external; + + let $f := fn:concat#4 + let $g := fn:concat#1 (: error: fn:concat requires at least 2 arguments :) + return $f(1, 2, 3, 4) (: returns "1234" :) + +### sum + + declare function sum($values as variadic array(xs:numeric)) { + if (array:size($values) = 1) then + $values + else + $values(1) + sum($values(2 to array:size($values))) + }; + +## Grammar + + ParamList ::= Param ("," Param)* ("," VariadicParam)? + VariadicParam ::= "$" EQName "as" "variadic" ArrayTest From 83ad48c8fc3b4f8964c38ba921da115c69bcdd28 Mon Sep 17 00:00:00 2001 From: Reece Dunn Date: Tue, 16 Oct 2018 12:19:27 +0100 Subject: [PATCH 2/7] variadic-function-arguments: clarify the grammar section --- variadic-function-arguments.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/variadic-function-arguments.md b/variadic-function-arguments.md index 2cf1402..586b765 100644 --- a/variadic-function-arguments.md +++ b/variadic-function-arguments.md @@ -70,7 +70,12 @@ Support user-defined functions like sum or product that take a variable number o $values(1) + sum($values(2 to array:size($values))) }; -## Grammar +## Grammar (Preliminary; Unverified) + +__Modified (Integration Points):__ ParamList ::= Param ("," Param)* ("," VariadicParam)? + +__New:__ + VariadicParam ::= "$" EQName "as" "variadic" ArrayTest From 59568f5571ad56d19939e5189ba3be73dac9dcbe Mon Sep 17 00:00:00 2001 From: "Reece H. Dunn" Date: Wed, 17 Oct 2018 07:41:38 +0100 Subject: [PATCH 3/7] [variadic function arguments]: Remove the reference to automatic array/sequence expansion to function arguments. --- variadic-function-arguments.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/variadic-function-arguments.md b/variadic-function-arguments.md index 586b765..1e88a29 100644 --- a/variadic-function-arguments.md +++ b/variadic-function-arguments.md @@ -17,7 +17,7 @@ If the function reference specifies an arity equal to one more than the number o When a function with variadic arguments is called, the arguments after the argument that corresponds with the last non-variadic parameter are collected into an array in the same order and passed to the variadic parameter. -A function with a variadic argument may be passed an array or sequence to that argument. If it is passed a sequence, the sequence is treated as if it was wrapped in an array constructor. +If any of these arguments are an array or sequence, that array or sequence will be included as is at the place in the variadic array it occurs in the argument list from the variadic parameter. For example, if the variadic parameter is the third parameter in a function definition, and an array is passed as the fourth parameter, that array will be the second argument of the variadic array passed to the declared function. ### Influences @@ -46,8 +46,6 @@ Support user-defined functions like sum or product that take a variable number o 1. MUST allow access to the variadic arguments within the function body of an XPath/XQuery expression or function declaration. -1. MAY allow passing arrays or sequences as the variadic parameter instead of passing separate arguments. - ## Examples ### fn:concat @@ -64,10 +62,7 @@ Support user-defined functions like sum or product that take a variable number o ### sum declare function sum($values as variadic array(xs:numeric)) { - if (array:size($values) = 1) then - $values - else - $values(1) + sum($values(2 to array:size($values))) + array:fold-left($values, 0, function ($a, $b) { $a + $b }) }; ## Grammar (Preliminary; Unverified) From 3440cdd30c3502e1412ba369330913cbed1cd2f5 Mon Sep 17 00:00:00 2001 From: "Reece H. Dunn" Date: Wed, 17 Oct 2018 08:05:34 +0100 Subject: [PATCH 4/7] [variadic function arguments]: Allow 0 arguments bound to the variadic function parameter. --- variadic-function-arguments.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/variadic-function-arguments.md b/variadic-function-arguments.md index 1e88a29..569728f 100644 --- a/variadic-function-arguments.md +++ b/variadic-function-arguments.md @@ -7,13 +7,19 @@ Allow support for a variable-length sequence of typed parameters to a function. ## Description -A variadic function parameter has at least 1 item. The upper bound is unbounded, but may be an implementation defined limit. +Variadic function parameters are defined using an `ArrayTest`. For example: -For a function with `N` non-variadic parameters and a variadic parameter, that function defines a set of functions in the static context with the specified function name, and arity of `N+1` upward to the maximum number of arguments supported by an implementation. + $mimetypes as variadic array(xs:string) + +In this example, `$mimetypes` is a *variadic function parameter*. A variadic function parameter must be the last parameter of a function defined by an inline function expression or function declaration. + +The *variadic parameter type* is the type of the `ArrayTest` associated with the variadic function parameter, or `item()` if it is not specified. + +A function definition where the last parameter is a variadic function parameter has a minimum arity equal to the number of non-variadic parameters, and an unbounded maximum arity. A function reference to a variadic function will behave the same as if the function was defined with the specified arity, or an error if there are fewer arguments than the requested arity. -If the function reference specifies an arity equal to one more than the number of non-variadic arguments (i.e. where the variadic size is 1), the last argument is treated as having a type equal to the union of the specified type and an array of the specified type. +If a named function reference is created with an arity equal to the number of parameters including the variadic function parameter, the type of the last parameter in the bound function is the variadic parameter type. When a function with variadic arguments is called, the arguments after the argument that corresponds with the last non-variadic parameter are collected into an array in the same order and passed to the variadic parameter. @@ -52,12 +58,13 @@ Support user-defined functions like sum or product that take a variable number o declare function fn:concat( $arg1 as xs:anyAtomicType?, - $args as variadic array(xs:anyAtomicType?) + $arg2 as xs:anyAtomicType?, + $other-args as variadic array(xs:anyAtomicType?) ) external; let $f := fn:concat#4 - let $g := fn:concat#1 (: error: fn:concat requires at least 2 arguments :) - return $f(1, 2, 3, 4) (: returns "1234" :) + let $g := fn:concat#2 + return ($f(1, 2, 3, 4), $g("a", "b")) (: returns ("1234", "ab") :) ### sum From 54441c06f990a2e66ea0a7fd3c549fc0507c4bd5 Mon Sep 17 00:00:00 2001 From: "Reece H. Dunn" Date: Wed, 17 Oct 2018 20:12:14 +0100 Subject: [PATCH 5/7] [variadic function arguments] Add more examples. --- variadic-function-arguments.md | 35 +++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/variadic-function-arguments.md b/variadic-function-arguments.md index 569728f..9df5884 100644 --- a/variadic-function-arguments.md +++ b/variadic-function-arguments.md @@ -34,7 +34,11 @@ There are many languages that have support for variadic function arguments, incl Define the `fn:concat` function in the XPath and XQuery Functions and Operators 3.1 specification using valid XPath/XQuery syntax, instead of hand-waiving the variadic nature of the function. -Support other vendor-specific functions that allow variadic arguments. +Support other vendor-specific functions that allow variadic arguments. These include: + +1. [out:format](http://docs.basex.org/wiki/Output_Module#out:format) -- BaseX +1. [xdmp:apply](https://docs.marklogic.com/xdmp:apply) -- MarkLogic +1. [sem:coalesce](https://docs.marklogic.com/sem:coalesce) -- MarkLogic Support user-defined functions like sum or product that take a variable number of arguments without requiring nested parenthesis (e.g. using `sum(1, 2, 3)` instead of `sum((1, 2, 3))`). @@ -52,6 +56,8 @@ Support user-defined functions like sum or product that take a variable number o 1. MUST allow access to the variadic arguments within the function body of an XPath/XQuery expression or function declaration. +1. MAY allow variadic arguments to be applied to annotation definitions. + ## Examples ### fn:concat @@ -68,10 +74,37 @@ Support user-defined functions like sum or product that take a variable number o ### sum +Using a function declaration (XQuery): + declare function sum($values as variadic array(xs:numeric)) { array:fold-left($values, 0, function ($a, $b) { $a + $b }) }; + sum(1, 2, 3) + +Using inline function expressions (XPath/XQuery): + + let $sum := function ($values as variadic array(xs:numeric)) { + array:fold-left($values, 0, function ($a, $b) { $a + $b }) + }; + return $sum(1, 2, 3) + +### rest:form-params (EXQuery RESTXQ) + + declare %annotation function rest:form-param( + $name as xs:string, + $param-reference as xs:string, + $default-values as variadic array(xs:string) + ) external; + +or with support for annotation declarations: + + declare annotation rest:form-param( + $name as xs:string, + $param-reference as xs:string, + $default-values as variadic array(xs:string) + ) for function; + ## Grammar (Preliminary; Unverified) __Modified (Integration Points):__ From 0dded843cf1e7e21d357c9360bf5faf5b9e1e129 Mon Sep 17 00:00:00 2001 From: "Reece H. Dunn" Date: Sat, 10 Nov 2018 20:56:46 +0000 Subject: [PATCH 6/7] variadic function arguments: Update the syntax to use '...'. --- variadic-function-arguments.md | 40 +++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/variadic-function-arguments.md b/variadic-function-arguments.md index 9df5884..ac36a29 100644 --- a/variadic-function-arguments.md +++ b/variadic-function-arguments.md @@ -7,13 +7,17 @@ Allow support for a variable-length sequence of typed parameters to a function. ## Description -Variadic function parameters are defined using an `ArrayTest`. For example: +\[Definition: *Variadic function arguments* match zero or more arguments at the end of the non-variadic arguments.\] - $mimetypes as variadic array(xs:string) +When `...` is added after the last parameter in a parameter list, that parameter +contains the arguments passed after the previous parameter as an `array`. If the +variadic parameter is given a type, the elements in that array has that type. -In this example, `$mimetypes` is a *variadic function parameter*. A variadic function parameter must be the last parameter of a function defined by an inline function expression or function declaration. - -The *variadic parameter type* is the type of the `ArrayTest` associated with the variadic function parameter, or `item()` if it is not specified. +> __Example__ +> +> declare function accept($mimetypes as xs:string ...) as xs:string external; +> +> In this example, `$mimetypes` is a *variadic function parameter* with the type `array(xs:string)`. A function definition where the last parameter is a variadic function parameter has a minimum arity equal to the number of non-variadic parameters, and an unbounded maximum arity. @@ -25,6 +29,7 @@ When a function with variadic arguments is called, the arguments after the argum If any of these arguments are an array or sequence, that array or sequence will be included as is at the place in the variadic array it occurs in the argument list from the variadic parameter. For example, if the variadic parameter is the third parameter in a function definition, and an array is passed as the fourth parameter, that array will be the second argument of the variadic array passed to the declared function. + ### Influences There are many languages that have support for variadic function arguments, including C/C++ and Java. Java supports variadic parameters by mapping them to an object array. @@ -42,6 +47,7 @@ Support other vendor-specific functions that allow variadic arguments. These inc Support user-defined functions like sum or product that take a variable number of arguments without requiring nested parenthesis (e.g. using `sum(1, 2, 3)` instead of `sum((1, 2, 3))`). + ### Requirements 1. MUST be backward compatible with XPath 3.1 and XQuery 3.1. @@ -58,6 +64,7 @@ Support user-defined functions like sum or product that take a variable number o 1. MAY allow variadic arguments to be applied to annotation definitions. + ## Examples ### fn:concat @@ -65,7 +72,7 @@ Support user-defined functions like sum or product that take a variable number o declare function fn:concat( $arg1 as xs:anyAtomicType?, $arg2 as xs:anyAtomicType?, - $other-args as variadic array(xs:anyAtomicType?) + $args as xs:anyAtomicType?... ) external; let $f := fn:concat#4 @@ -76,15 +83,15 @@ Support user-defined functions like sum or product that take a variable number o Using a function declaration (XQuery): - declare function sum($values as variadic array(xs:numeric)) { + declare function sum($values as xs:numeric ...) { array:fold-left($values, 0, function ($a, $b) { $a + $b }) }; sum(1, 2, 3) -Using inline function expressions (XPath/XQuery): +Using inline function expressions, untyped (XPath/XQuery): - let $sum := function ($values as variadic array(xs:numeric)) { + let $sum := function ($values ...) { array:fold-left($values, 0, function ($a, $b) { $a + $b }) }; return $sum(1, 2, 3) @@ -94,7 +101,7 @@ Using inline function expressions (XPath/XQuery): declare %annotation function rest:form-param( $name as xs:string, $param-reference as xs:string, - $default-values as variadic array(xs:string) + $default-values as xs:string ... ) external; or with support for annotation declarations: @@ -102,15 +109,18 @@ or with support for annotation declarations: declare annotation rest:form-param( $name as xs:string, $param-reference as xs:string, - $default-values as variadic array(xs:string) + $default-values as xs:string ... ) for function; -## Grammar (Preliminary; Unverified) + +## Grammar __Modified (Integration Points):__ - ParamList ::= Param ("," Param)* ("," VariadicParam)? + ParamList ::= Param ("," Param)* "..."? + -__New:__ +## Version History - VariadicParam ::= "$" EQName "as" "variadic" ArrayTest +1. Initial proposal. +1. Changed the syntax to use `...` as proposed by Michael Kay. From 6f0c3adaab50274c36421affe688fc9b95064eb5 Mon Sep 17 00:00:00 2001 From: "Reece H. Dunn" Date: Sun, 11 Nov 2018 11:39:38 +0000 Subject: [PATCH 7/7] variadic function arguments: Be more precise in the specification of the function arity; add an ArrowFunctionSpecifier example. --- variadic-function-arguments.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/variadic-function-arguments.md b/variadic-function-arguments.md index ac36a29..04914a9 100644 --- a/variadic-function-arguments.md +++ b/variadic-function-arguments.md @@ -19,9 +19,9 @@ variadic parameter is given a type, the elements in that array has that type. > > In this example, `$mimetypes` is a *variadic function parameter* with the type `array(xs:string)`. -A function definition where the last parameter is a variadic function parameter has a minimum arity equal to the number of non-variadic parameters, and an unbounded maximum arity. +The function arity is now a range instead of a scalar. That is, a function with `P` parameters has an arity of `[P..P]` if it is not variadic, and an arity of `[P-1..INF]` if it is variadic. This is an inclusive range. __NOTE:__ `P-1` is used here as a variadic function parameter matches 0 or more function arguments. -A function reference to a variadic function will behave the same as if the function was defined with the specified arity, or an error if there are fewer arguments than the requested arity. +A named function reference or argument list matches a function's arity if the number of arguments is within the arity range. If no function is located with the requested arity, an XPST0017 error is raised. If a named function reference is created with an arity equal to the number of parameters including the variadic function parameter, the type of the last parameter in the bound function is the variadic parameter type. @@ -96,6 +96,11 @@ Using inline function expressions, untyped (XPath/XQuery): }; return $sum(1, 2, 3) +### Interaction with ArrowFunctionSpecifier + + 1 => sum(2) (: adds '1' to the start of the variadic parameters :) + "%d" => out:format(2) (: passes "%d" to the only non-variadic parameter :) + ### rest:form-params (EXQuery RESTXQ) declare %annotation function rest:form-param(