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

Support unbounded variadic functions on map parameter keys #162

Closed
rhdunn opened this issue Sep 27, 2022 · 6 comments
Closed

Support unbounded variadic functions on map parameter keys #162

rhdunn opened this issue Sep 27, 2022 · 6 comments
Labels
Feature A change that introduces a new feature Propose Closing with No Action The WG should consider closing this issue with no action XPath An issue related to XPath

Comments

@rhdunn
Copy link
Contributor

rhdunn commented Sep 27, 2022

Where a parameter is defined as a map, then named/keyword arguments bind to keys in that map if the named/keyword argument does not match a parameter name in that function. For example, fn:serialize($data, method: "json").

Motivation

There are several functions that take an option map in XQFO. It can be clunky to construct the map options when calling these functions.

The option map is a common pattern in other implementations. Specifically, MarkLogic makes use of that pattern.

Note

If the argument name is an NCName, the xs:NCName value should be cast to the map's key type using the XQFO type/value casting rules.

The argument name should support string literals, as map keys can contain spaces. In this case, the xs:string type is cast to the map's key type using the XQFO type/value casting rules.

The #159 proposal allows QNames for the argument names in order to support parameters that are QNames. When binding to a map key an error (static or dynamic) should be raised.

@rhdunn rhdunn added XPath An issue related to XPath Feature A change that introduces a new feature labels Sep 27, 2022
@dnovatchev
Copy link
Contributor

I like this proposal.

It can be carried one step further: If the function has two or more parameters whose type is a map, then providing the value for a specific map option can still be done by prefixing it with the name of the map parameter, like:

funWith2MapParams($data, MapParam1?method := "json", MapParam2?method := "SomethingElse", )

@johnlumley
Copy link

What happens if an (optional) argument of type map has a keyword that is the same as that of a key of the defined map type? E.g.
foo($a, $bar as map(*))
and we call
foo(123, bar:=map{'a':1})
Is the value of the second argument in the function body now
a map{'a':1} or a map{'bar':map{'a':1}} ?

@michaelhkay
Copy link
Contributor

michaelhkay commented Mar 13, 2023

I like the way this is going, but there are some difficulties: not least, the fact that we need to count the number of arguments in the function call before we know which function we are actually calling. To achieve this, I think we need a syntactic distinction between arguments used to set options, and those that bind to regular named parameters.

I propose the following.

No changes to the syntax of function declarations.

In a static function call, we allow a KeywordArgument to take the alternative form:

KeywordArgument ::= OptionArgument | ...
OptionArgument ::= '?' (NCName | string-literal) ':=' ExprSingle

To compute the effective arity of a static function call, we take the number of arguments that are not OptionArguments, and add one if there are one or more OptionArguments. This enables us to identify the function being called. If there are one or more OptionArguments, they are assembled into a map, and this map is supplied as the value of the last parameter in the function definition. For example given the function call

fn:serialize($input, ?method:='json', ?indent:=true())

we identify this as a call on fn:serialize#2, and convert the function call into the equivalent

fn:serialize($input, options := map{'method':'json', 'indent':true()})

Note: we could add the possibility of writing options?indent := true() as suggested, but I'm not convinced that this is really useful. It makes the rules for deciding which function is being called, based on the number of arguments in the call, quite a bit more complicated.

@ChristianGruen ChristianGruen changed the title Proposal to support unbounded variadic functions on map parameter keys. Support unbounded variadic functions on map parameter keys Apr 27, 2023
@michaelhkay
Copy link
Contributor

I propose the following.

(a) function declarations/definitions do not change.

(b) a function call may take the form `fn:serialize($input; method:='json', indent:=true())

Everything after the semicolon counts as one argument, and this argument is bound to the last parameter in the function definition. The value of the argument is a map formed from the supplied keyword/value pairs. The keywords must be in the form of NCNames.

Possible variations:

  • Allow string literals as the keywords (feels unnecessary to me, all our current options are NCNames)
  • Use a different delimiter ('=' or ':')
  • Bind the argument to the parameter named "options" rather than to the last parameter (one benefit would be parser convenience, it means that a function call using ";" can be converted to a conventional static function call without knowing any details of the function definition. Another benefit would be extensibility of function definitions; it becomes possible to add another parameter after the options parameter should this be necessary. However, making "options" a magic name seems ugly.)

@michaelhkay
Copy link
Contributor

In PR #1071, we are proposing that it should become possible to write

fn:serialize($input, {'method':'json', 'indent':true()})

which seems about as good as:

fn:serialize($input; method:='json', indent:=true())

So I propose that we should treat acceptance of PR #1071 as meaning we can close this issue with no further action.

@michaelhkay michaelhkay added the Propose Closing with No Action The WG should consider closing this issue with no action label May 8, 2024
@ndw
Copy link
Contributor

ndw commented May 14, 2024

The CG agreed to close this issue without further action at meeting 077.

@ndw ndw closed this as completed May 14, 2024
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 Propose Closing with No Action The WG should consider closing this issue with no action XPath An issue related to XPath
Projects
None yet
Development

No branches or pull requests

5 participants