This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 29426 - add default parameters
Summary: add default parameters
Status: NEW
Alias: None
Product: XPath / XQuery / XSLT
Classification: Unclassified
Component: XQuery 3.2 Use Cases and Requirements (show other bugs)
Version: Candidate Recommendation
Hardware: PC Linux
: P2 normal
Target Milestone: ---
Assignee: Jonathan Robie
QA Contact: Mailing list for public feedback on specs from XSL and XML Query WGs
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-02-07 12:19 UTC by Benito van der Zander
Modified: 2016-02-09 03:05 UTC (History)
0 users

See Also:


Attachments

Description Benito van der Zander 2016-02-07 12:19:29 UTC
It is straightforward to define default parameters for named functions:
	Param	   ::=   	"$" EQName TypeDeclaration?
becomes
	Param	   ::=   	"$" EQName TypeDeclaration? (":=" VarDefaultValue)?

(under the constraint that a param with default value must not be followed by a param without)
	
	
A function declaration 	
    declare function local:foobar($a, $b as xs:integer := 123, $c := "xyz")	{ ... }

is then equivalent to 

    declare function local:foobar($a, $b as xs:integer, $c)	{ ... };
    declare function local:foobar($a, $b)	{ local:foobar($a, $b, "xyz") };
    declare function local:foobar($a)	{ local:foobar($a, 123, "xyz") };
 
This is very simple. Calling, partial application and # references work just as they work with those three separate definitions.

However, it should be considered a single function (or a set of functions with different arity), because it will lead to a definition of default parameters for the harder case of anonymous functions.

With the same grammar modification as above we get

    let $foobar := function ($a, $b as xs:integer := 123, $c := "xyz")	{ ... }

Calling it should work like the local:foobar above, i.e. $foobar(1) = local:foobar(1); $foobar(1,2) = local:foobar(1,2); ...

The same holds for partial application, e.g. $foobar(?) or foobar(1,?) is just the same as local:foobar(?) or local:foobar(1, ?).

We could even allow partial application with default parameters. E.g. $foobar(?, ? as xs:integer := 123, ? := "xyz") which would turn a function without default parameters to a function with default parameters.

The type of a such a function is also simple. The function can be called with different arity, so it is a set of functions with different arity. Thus the type of this set is the union type of the typse of all the functions in the set. (although types could also be extended to a type function (item(), xs:integer, xs:string := "foobar", xs:int := 123). A function of this target type T could be called with 3 different arities, so a function F has type T, if the minimal arity of F is at most the minimal arity of T, the maximal arity of F is at least the maximal arity of T and for each arity in between the types match as for a single arity function )


Function coercion always coerces to some target type, a type that has a fixed arity or is function(*). So it just picks the function with that arity from the set and ignores all the others. (if the target type also has default parameters and thus multiple arities, it is a little more complicated. The value is a set of functions F, with different arities. The target type has a set of arities At. For each A in At, we take the function f with the smallest arity of the set { f in F | arity of f >= A}. If no such function exists, it is an error. If the arity of f is greater than the maximal arity of T it is also an error. If the arity of f is greater than A, the remaining parameters of f are filled with the default parameters of T. This results in a function of arity A that calls function f. (An other explanation: The coerced function has so many total and default parameters as the target type, and calls the original function with its original default parameters. The default parameters of the target type are only used at the beginning, i.e. if there is a parameter that is optional with a default value in the target type, but does not have a default value in the original function)


The last non-obvious question is what fn:function-arity should return.
It is reasonable to return the maximum, so function-arity($foobar) = 3, as the function can be used as function with arity 3. 
There is no need to know the different arities.
Although it could also be modified to return xs:integer+, i.e. function-arity($foobar) == (1,2,3)





 

Now that default parameters are defined, we can finally come to the point of all of this.
On their own these parameters are not really useful, since you can just define multiple functions.
However, with default parameters on anonymous functions the array and map types can be redefined.

In JSONiq you can write $map() to get all keys of a map and $array() to get the content of the entire array.
This is very useful. It is even more useful than ?*, since you can get the map values from the map keys, 
but not the other way around, so it is better to have an easy syntax for the map keys.

Using the default parameters, the map (and array) become a function($key := <some implicit value that returns the keys/content>) { ... }.

Then $map() and $map(key) are well-defined for some map $map. (as well as $array(), $array(index))

(you cannot expect people to rewrite all their JSONiq queries)
Comment 1 Jonathan Robie 2016-02-09 03:05:29 UTC
It's too late for XQuery 3.1, assigning to 3.2.