xsl:function with optional parameters

Just putting my thoughts down here in case it helps me come up with a solution, or in case anyone else can offer insights.

Allowing xsl:function to define optional parameters is easy enough, it's largely a matter of removing the restriction that you currently aren't allowed to say required="no".

The interesting part is, what happens to the rules for overriding declarations?

As regards "old-style" overriding using import precedence, we currently say:

An xsl:function <https://www.w3.org/TR/xslt-30/#element-function> declaration defines a stylesheet function <https://www.w3.org/TR/xslt-30/#dt-stylesheet-function> which forms a component <https://www.w3.org/TR/xslt-30/#dt-component> in its containing package <https://www.w3.org/TR/xslt-30/#dt-package>, unless 

there is another stylesheet function <https://www.w3.org/TR/xslt-30/#dt-stylesheet-function> with the same name and arity <https://www.w3.org/TR/xslt-30/#dt-arity>, and higher import precedence <https://www.w3.org/TR/xslt-30/#dt-import-precedence>,
So what happens if a module with higher import precedence declares a function with an overlapping arity range? Do we try and override some of the arities and not others (a "partial eclipse")? Allowing that level of complexity isn't useful, so is there an easy way to avoid it?

I think the simplest rule is that it's an error to have declarations D and E, where the import precendence of D is higher than that of E, if D's arity range includes part but not the whole of the arity range of E.

Now what about the existing error condition?
[ERR XTSE0770]  <>It is a static error <https://www.w3.org/TR/xslt-30/#dt-static-error> for a package <https://www.w3.org/TR/xslt-30/#dt-package> to contain two or more xsl:function <https://www.w3.org/TR/xslt-30/#element-function> declarations with the same expanded QName <https://www.w3.org/TR/xslt-30/#dt-expanded-qname>, the same arity <https://www.w3.org/TR/xslt-30/#dt-arity>, and the same import precedence <https://www.w3.org/TR/xslt-30/#dt-import-precedence>, unless there is another xsl:function <https://www.w3.org/TR/xslt-30/#element-function> declaration with the same expanded QName <https://www.w3.org/TR/xslt-30/#dt-expanded-qname> and arity, and a higher import precedence.


I think this becomes:

[ERR XTSE0770]  <>It is a static error <https://www.w3.org/TR/xslt-30/#dt-static-error> for a package <https://www.w3.org/TR/xslt-30/#dt-package> to contain two or more xsl:function <https://www.w3.org/TR/xslt-30/#element-function> declarations with the same expanded QName <https://www.w3.org/TR/xslt-30/#dt-expanded-qname>, overlapping arity <https://www.w3.org/TR/xslt-30/#dt-arity> ranges, and the same import precedence <https://www.w3.org/TR/xslt-30/#dt-import-precedence>, 
unless there is another xsl:function <https://www.w3.org/TR/xslt-30/#element-function> declaration with the same expanded QName <https://www.w3.org/TR/xslt-30/#dt-expanded-qname>,  a higher import precedence, and an arity range that subsumes all of their arity ranges.


Now what about new-style overriding using xsl:override and packages.

I attempted some rules in the current draft, but I think the simplest is to require a close match between the overriding declaration and the overridden declaration.

Firstly, I think the "symbolic identifier" of a function component should use its maximum arity.

The 3.0 rules in 3.5.3.3 are:

Two functions with the same name and arity are compatible if and only if they satisfy all the following rules:
The declared types of the arguments (defaulting to item()*) are pairwise identical <https://www.w3.org/TR/xslt-30/#dt-identical-types>.
The declared return types (defaulting to item()*) are identical <https://www.w3.org/TR/xslt-30/#dt-identical-types>.
The effective value of the new-each-time attribute on the overriding function is the same as its value on the overridden function.
If the overridden function specifies streamable="yes" then the overriding function also specifies streamable="yes", and in addition, it has the same posture <https://www.w3.org/TR/xslt-30/#dt-posture> and sweep <https://www.w3.org/TR/xslt-30/#dt-sweep> as the function that it overrides.

I think this then becomes:

Two functions with the same symbolic identifier are compatible if and only if they satisfy all the following rules:
  0. They have the same arity range [which implies that they have the same number of required and optional arguments]
The declared types of the arguments (defaulting to item()*) are pairwise identical <https://www.w3.org/TR/xslt-30/#dt-identical-types>.
The declared return types (defaulting to item()*) are identical <https://www.w3.org/TR/xslt-30/#dt-identical-types>.
The effective value of the new-each-time attribute on the overriding function is the same as its value on the overridden function.
If the overridden function specifies streamable="yes" then the overriding function also specifies streamable="yes", and in addition, it has the same posture <https://www.w3.org/TR/xslt-30/#dt-posture> and sweep <https://www.w3.org/TR/xslt-30/#dt-sweep> as the function that it overrides.
which then leaves the question of whether the names of the parameters and their default values can differ. I don't see a problem with allowing the default values to differ. Allowing the names to differ is problematic because the overriding function is no longer substitutable, as the names are now visible as keywords in a function call. But disallowing name changes is difficult because it's allowed in 3.0. The only solution I can think of is to allow name changes, but disregard them: the overriding function is treated "as if" it used the same parameter names as the overridden function.

Any thoughts welcome.

This stuff isn't easy!

Michael Kay

Received on Thursday, 29 September 2022 16:51:55 UTC