Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specify optional parameters to create bounded variadic functions #64

Closed
rhdunn opened this issue Mar 12, 2021 · 7 comments
Closed

Specify optional parameters to create bounded variadic functions #64

rhdunn opened this issue Mar 12, 2021 · 7 comments
Labels
Feature A change that introduces a new feature XPath An issue related to XPath

Comments

@rhdunn
Copy link
Contributor

rhdunn commented Mar 12, 2021

The current Editor's Draft for XPath and XQuery define a %variadic("bounded") function type, but does not define a syntax for specifying these.

Grammar

ParamList ::= RequiredParamList ( "," OptionalParamList )?
RequiredParamList ::= Param ("," Param)*
Param ::= "$" EQName TypeDeclaration?
OptionalParamList ::= OptionalParam ("," OptionalParam)*
OptionalParam ::= Param ":=" ExprSingle

Note:

I've followed the structure of positional and keyword arguments here, so the optional parameters are only valid at the end of the function. If it is decided that optional parameters can be declared anywhere in the parameter list, the grammar simplifies to:

ParamList ::= Param ("," Param)*
Param ::= "$" EQName TypeDeclaration? ( ":=" ExprSingle )?

Semantics

[Definition: a parameter is an optional parameter if it has a default value specified using the := ExprSingle syntax.] Optional parameters affect the value of R (the number of parameters that do not have a default value) in the 4.4.1 Static Functions section.

Notes

There are open questions on what to allow in the default value expression. Specifically, how to support things like the context item for functions such as fn:data#0 that use the context item if not specified (e.g. when used at the end of a path expression).

An investigation should be done on the standard functions and vendor built-in functions to see what values they take as defaults.

@rhdunn
Copy link
Contributor Author

rhdunn commented Apr 12, 2021

The following table lists the default values for the various parameters of the built-in functions. Where the "Changed?" column has a value of "yes", the parameter and function need signature and logic changes to support the default value; these changes are described in separate issues (#69 and #70).

Using the default values means that the combined functions depend on all the context items that the currently separate versions do. That is, if the 2-argument version depends on the default collation, but the 3-argument version does not, then with the default values applied both versions depend on the default collation.

Function Parameter Default Value Changed?
array:sort $collation () no
array:sort $key fn:data#1 no
array:subarray $length () yes
map:merge $options n/a [1] no
fn:adjust-date-to-timezone $timezone () no
fn:adjust-dateTime-to-timezone $timezone () no
fn:adjust-time-to-timezone $timezone () no
fn:analyze-string $flags "" no
fn:base-uri $node . [2] no
fn:collation-key $collation () yes
fn:collection $uri () no
fn:compare $collation () yes
fn:contains $collation () yes
fn:contains-token $collation () yes
fn:copy-of [XSLT] $input . [2] no
fn:data $input . [2] no
fn:deep-equal $collation () yes
fn:differences $collation () yes
fn:differences $options map {} [3] yes
fn:distinct-values $collation () yes
fn:document [XSLT] $base-node () yes
fn:document-uri $node . [2] no
fn:element-with-id $node . [2] no
fn:ends-with $collation () yes
fn:error $code () no
fn:error $description [4] no
fn:error $error-object [4] no
fn:format-date $language () [5] no
fn:format-date $calendar () [5] no
fn:format-date $place () [5] no
fn:format-dateTime $language () [5] no
fn:format-dateTime $calendar () [5] no
fn:format-dateTime $place () [5] no
fn:format-integer $language () no
fn:format-number $decimal-format-name () no
fn:format-time $language () [5] no
fn:format-time $calendar () [5] no
fn:format-time $place () [5] no
fn:function-available [XSLT] $arity () yes
fn:generate-id $node . [2] no
fn:has-children $node . [2] no
fn:highest $collation () no
fn:highest $key fn:data#1 no
fn:id $node . [2] no
fn:idref $node . [2] no
fn:index-of $collation () yes
fn:json $options n/a [1] no
fn:json-doc $options n/a [1] no
fn:json-to-xml $options n/a [1] no
fn:key [XSLT] $top / [2] no
fn:lang $node . [2] no
fn:load-xquery-module $options n/a [1] no
fn:local-name $node . [2] no
fn:lowest $collation () no
fn:lowest $key fn:data#1 no
fn:matches $flags "" no
fn:max $collation () yes
fn:min $collation () yes
fn:name $node . [2] no
fn:namespace-uri $node . [2] no
fn:nilled $node . [2] no
fn:node-name $node . [2] no
fn:normalize-space $value . [2] no
fn:normalize-unicode $form "NFC" no
fn:number $node . [2] no
fn:parse-json $options n/a [1] no
fn:path $node . [2] no
fn:random-number-generator $seed () no
fn:replace $flags () [6] yes
fn:replace $action () no
fn:resolve-uri $base () yes
fn:round $precision 0 no
fn:round-half-to-even $precision 0 no
fn:serialize $params () no
fn:sort $collation () no
fn:sort $key fn:data#1 no
fn:starts-with $collation () yes
fn:string $item . [2] no
fn:string-join $separator "" no
fn:string-length $value fn:string(.) [2] no
fn:subsequence $length () yes
fn:substring $length () yes
fn:substring-after $collation () yes
fn:substring-before $collation () yes
fn:sum $zero 0 [7] no
fn:tokenize $pattern () yes
fn:tokenize $flags "" no
fn:trace $label [4] no
fn:uniform $collation () yes
fn:unique $collation () yes
fn:unparsed-entity-public-id [XSLT] $doc . [2] no
fn:unparsed-entity-uri [XSLT] $doc . [2] no
fn:unparsed-text $encoding () yes
fn:unparsed-text-available $encoding () yes
fn:unparsed-text-lines $encoding () yes
fn:uri-collection $uri () no
fn:xml-to-json $options n/a [1] no

[1] The function is map-variadic, so those rules will supply the default map {} value.

[2] The default value in these cases cannot be evaluated statically, but require passing the context item at the point at which the function call is evaluated.

[3] The default is specified here as the $collation parameter also has a default value, so the following parameters should also have specified default values.

[4] The $description, $error-object, and $label arguments have implementation-defined default values. As such, the 0- and 1-argument versions of fn:error can be combined, but the 2- and 3-argument versions cannot, nor can fn:trace.

[5] The function gains additional 3- and 4-argument versions due to it having default values for the last 3 parameters.

[6] By using the 5-argument version with default arguments, the $flags argument will be optional in the 4-argument case, as it is in the 5-argument version. As $flags is optional in the 5-argument version, it does not need changing to support default values.

[7] The 1-argument version of the function will have a return type of xs:anyAtomicType? when the default value is used in the 2-argument version.

@rhdunn
Copy link
Contributor Author

rhdunn commented Apr 12, 2021

Given the above analysis, and having experimented with optional parameters, there are two possibilities for defining the values for the optional arguments:

  1. keep the ExprSingle as part of the above grammar, and define an error if the result is not a constant value, ., or / (or possibly extended to any path expression);
  2. define a ConstExprSingle symbol (and others as necessary) to limit the result to constant values (numeric and string literals, named function references, empty sequences, and empty or constant maps), ., or /.

Evaluating Default Values

  1. Default values are evaluated using the static context of the declaration where the default value is specified. This means that statically-known namespaces, default element and type namespaces, statically-known functions, etc. are evaluated from the function declaration. The exceptions to this are the context item and focus, which are deferred to when the function is called.

  2. If the default value of the parameter is ., the function is ·context-dependent· and ·focus-dependent· when no value is passed to that parameter. The context item is determined at the point at which the function is called.

Example:

If the function is called as a step in a path expression, the context item is the context item created during the evaluation of the previous step. The context item is the inner focus context item at the point of the function call as described in section 4.6.1.1 Path operator (/).

  1. If the default value of the parameter is a path expression, the function is ·context-dependent· and ·focus-dependent· when no value is passed to that parameter. The value of the expression is the result of the path expression using the current context item as the initial step context.

Example:

Using / as the default value uses the root of the document bound to the context item at the point at which the function is called.

  1. Otherwise, if the default value is not a statically known value, an XPST#### error is raised.

@rhdunn rhdunn added XPath An issue related to XPath XQuery An issue related to XQuery Feature A change that introduces a new feature labels Sep 14, 2022
@dnovatchev dnovatchev removed the XQuery An issue related to XQuery label Sep 22, 2022
@rhdunn
Copy link
Contributor Author

rhdunn commented Sep 25, 2022

I wonder if it makes sense to restrict this to only defining and allowing constant value expressions, and then having separate issues for how to handle the . and / default values.

@rhdunn
Copy link
Contributor Author

rhdunn commented Sep 25, 2022

Here are some possible designs to handle . and /. Note: I'm in favour of design 2.

Design 1

A possible way for supporting . and / would be to use := ->{ . } and := ->{ / } respectively. For this to work, we would need the following new behaviour...

  1. If the default value of a parameter is an inline function, that function must have 0 parameters. The static context of that function is the current static context.
  2. When evaluating a static function call, if the default value is a 0-arity function then that function is evaluated at this point with the static context of the caller.

Note: The way this is defined would mean that you can't pass a 0-arity function reference as a default parameter.

Design 2

Another possibility is to use a variant of design 1, but define a DefaultExpr:

OptionalParam ::= Param ":=" OptionalParamValue
OptionalParamValue ::= EmptySequence | Literal | NamedFunctionRef | DefaultExpr
EmptySequence := "(" ")"
DefaultExpr := "default" EnclosedExpr

Here, DefaultExpr would allow := default { . } for context and focus dependent functions, and := default { / } for fn:key.

The semantics of DefaultExpr would be:

  1. You can only use DefaultExpr within the definition of an OptionalParam (as restricted by the grammar).
  2. If the default value of a parameter is a default expression, the static context of that expression is the current static context when statically resolving the definitions within that expression (i.e. functions, variables, etc.). If a default expression contains a ., path expression, or anything else that depends on the dynamic context, then that evaluation is deferred (see Evaluating Static Function Calls).
  3. In "Evaluating Static Function Calls", if an optional parameter value is a default expression then that expression is evaluated using the dynamic context of the caller, and the result is bound to that parameter.

@michaelhkay
Copy link
Contributor

michaelhkay commented Sep 25, 2022

Is there any reason not to allow the default value to be any expression? The semantics are that the expression is evaluated in the dynamic context of the function call. This allows the default value for $collation functions such as fn:compare() to be expressed as $collation := fn:default-collation().

Note that XSLT allows a named template to be defined with optional parameters (for example it allows <xsl:param name="collation" select="default-collation()"/> and in XSLT we would want to use the same syntax and semantics for functions if at all possible.

The static context, of course, doesn't include the local variables of the caller. But (in the XSLT case) it does include global variables.

@rhdunn
Copy link
Contributor Author

rhdunn commented Sep 26, 2022

I'm happy with that.

So to confirm, := . will evaluate the context item at the point where the function is called (Evaluating Static Function Calls), likewise for := /?

If that is the case, we can just have:

OptionalParam ::= Param ":=" ExprSingle

Otherwise, we would need the DefaultExpr defined above:

OptionalParam ::= Param ":=" ( ExprSingle | DefaultExpr )
DefaultExpr := "default" EnclosedExpr

@ChristianGruen ChristianGruen added this to the QT 4.0 milestone Oct 14, 2022
@ChristianGruen ChristianGruen removed this from the QT 4.0 milestone Apr 27, 2023
@ChristianGruen ChristianGruen changed the title [XPath] [XQuery] Add a syntax for specifying optional parameters to create bounded variadic functions. Add a syntax for specifying optional parameters to create bounded variadic functions. Apr 27, 2023
@ChristianGruen ChristianGruen changed the title Add a syntax for specifying optional parameters to create bounded variadic functions. Specify optional parameters to create bounded variadic functions May 2, 2023
@michaelhkay
Copy link
Contributor

Closing this as this is effectively what we ending up implementing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature A change that introduces a new feature XPath An issue related to XPath
Projects
None yet
Development

No branches or pull requests

4 participants