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

Defining names for parameters on typed function tests #1136

Closed
rhdunn opened this issue Apr 7, 2024 · 11 comments · Fixed by #1696
Closed

Defining names for parameters on typed function tests #1136

rhdunn opened this issue Apr 7, 2024 · 11 comments · Fixed by #1696
Labels
Enhancement A change or improvement to an existing feature PR Pending A PR has been raised to resolve this issue XPath An issue related to XPath

Comments

@rhdunn
Copy link
Contributor

rhdunn commented Apr 7, 2024

When defining the type of a higher-order function parameter, you cannot currently specify the names of the parameters of that higher-order function.

Allowing this can be useful for variou reasons:

  1. documenting the parameter names in the function signature -- this makes it clear looking at the function in an IDE, etc. what the parameters are;
  2. making the specs clearer by referring to the parameters by name;
  3. allowing a processor to provide better error messages by referring to the parameters names, e.g. when there is a type conversion error;
  4. allowing a user to reference the parameter by name if we enable this to resolve named keyword argments (which is currently being discussed in Partial function application: Keywords and placeholders #1114).

Thus, you could declare e.g. index-where like this:

declare function fn:index-where(
  $input as item()*,
  $predicate as function(
    $item as item(),
    $position as xs:integer
  ) as xs:boolean
) as xs:integer* {
  (: ... :)
};
@ChristianGruen
Copy link
Contributor

Thanks for the separate proposal.

I’m not 100% sure I understand how 4. could look like in practice. Could you add a little example for it?

@rhdunn
Copy link
Contributor Author

rhdunn commented Apr 7, 2024

declare function fn:index-where(
  $input as item()*,
  $predicate as function(
    $item as item(),
    $position as xs:integer
  ) as xs:boolean
) as xs:integer* {
  for $it at $pos in $input
  where $predicate(item := $it, position := $pos)
  return $pos
};

Here, the processor resolves $predicate in the function body to the parameter declaration. That has a static type which defines the parameter names of the function bound to that parameter. That static type is used to resolve the named keywords.

@ChristianGruen
Copy link
Contributor

ChristianGruen commented Apr 7, 2024

I wonder how that would go hand in hand with the existing semantics:

  • Currently, the function item fn:count#1 has the type function(item()*) as xs:integer.
  • With the proposal, I assume the type would change to function($input as item()*) as xs:integer.
  • Could this function item be supplied as an argument for a parameter with the type function($value as item()*) as xs:integer?

@ChristianGruen ChristianGruen added XPath An issue related to XPath Enhancement A change or improvement to an existing feature labels Apr 7, 2024
@michaelhkay
Copy link
Contributor

michaelhkay commented Apr 7, 2024

This proposal introduces some static type inferencing into the language, something which we have previously avoided (except for the limited purpose of streamability analysis in XSLT). If we keep it very tightly constrained -- associating the explicitly declared type of a variable or parameter with references to that variable or parameter -- then this might be manageable. But I worry that it could easily feature-creep into something more complex.

Consider

declare function fn:index-where(
  $input as item()*,
  $predicate as (function(
    $item as item(),
    $position as xs:integer
  ) as xs:boolean)?
) as xs:integer* {
  let $actual-predicate := $predicate otherwise true#0
  for $it at $pos in $input
  where $actual-predicate(item := $it, position := $pos)
  return $pos
};

This isn't going to work because $actual-predicate doesn't have a type declaration providing the parameter names.

He could try:

let $actual-predicate as function(
    $item as item(),
    $position as xs:integer
  ) as xs:boolean := $predicate otherwise true#0

but is this actually usable?

To make it more usable, we have to start introducing more complex type inferencing rules.

Even without this, we're making life tougher for implementations -- for example you can't now inline a variable reference without retaining information from its type declaration. To what benefit?

@rhdunn
Copy link
Contributor Author

rhdunn commented Apr 7, 2024

It would make sense for fn:count#1, etc. to keep the parameter names as part of the typed function test. -- This would allow the use of keyword arguments in that case as I discussed in the other thread.

I think it makes sense for function coercion rules, subsumption rules, etc. to allow different names -- otherwise there would be incompatibilities with 3.1 -- and use the names in the nearest scope.

That is, given:

let $f := fn:count#1 return $f(input := (1, 2))

the fn:count#1 expression resolves to the static type function($input as item()*) as xs:integer as you note. The variable $f inherits that inferred static type. And the dynamic call to $f(...) makes use of that static type.

And given:

let $f as function($values as item()*) as xs:integer := fn:count#1
return $f(values := (1, 2))

the variable $f provides a specific static type. And the dynamic call to $f(...) makes use of that specific static type.

@rhdunn
Copy link
Contributor Author

rhdunn commented Apr 7, 2024

@michaelhkay I'm happy to keep this constrained, such that your $actual-predicate example would not be able to use named parameters without the dynamic proposal from @ChristianGruen. -- This goes along the lines of your approach of introducing small, constrained features rather than trying to do everything at once.

There are two parts to this proposal:

  1. supporting naming the parameters on a function test as a purely documentational feature -- i.e. where it does not affect the semantics of the function test;
  2. extending the use of named keywords to the case where the static type of a variable/parameter is a function test with parameter names, or via a named function reference.

I don't expect this specific proposal to go any/much farther than that. Doing so would require the dynamic proposal that @ChristianGruen is putting forward.

@ChristianGruen
Copy link
Contributor

@ChristianGruen. -- This goes along the lines of your approach of introducing small, constrained features rather than trying to do everything at once.

An even smaller step (hopefully not too small) would be to introduce optional parameter names, but to utilize them only for documentation and error messages. This would address reason 1-3 of this proposal.

Closely related: #981.

@rhdunn
Copy link
Contributor Author

rhdunn commented Apr 7, 2024

I'm happy to treat 1-3 and 4 as two separate proposals.

@michaelhkay
Copy link
Contributor

I do think we should avoid the "thin end of the wedge" effect of static type inferencing. I don't think it would be acceptable to allow parameter names on $param(....) but not on $param[3](....) or $param()(....) or $record?callback(....).

@michaelhkay
Copy link
Contributor

I agree that allowing names purely for documentation purposes seems a sensible idea.

It's hard to separate this, however, from the fact that according to the data model, a function item has parameters with names. Currently there is no way of determining what the names are, and I don't think there is anything in the language that would be any different if they didn't have names, but we should make a decision whether to retain the names and make use of them, or to drop them.

@ChristianGruen
Copy link
Contributor

I agree that allowing names purely for documentation purposes seems a sensible idea.

It's hard to separate this, however, from the fact that > we should make a decision whether to retain the names and make use of them, or to drop them.

Now that we introduce keyword parameters with version 4, I think it would be just consistent to keep the names as well.

@ndw ndw added the PRG-revisit Categorized as "needs revisiting" at the Prague f2f, 2024 label Jun 4, 2024
@michaelhkay michaelhkay added PR Pending A PR has been raised to resolve this issue and removed PRG-revisit Categorized as "needs revisiting" at the Prague f2f, 2024 labels Jan 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement A change or improvement to an existing feature PR Pending A PR has been raised to resolve this issue XPath An issue related to XPath
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants