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 24478 - [xslt 3.0] Static variables and import precedence
Summary: [xslt 3.0] Static variables and import precedence
Status: CLOSED FIXED
Alias: None
Product: XPath / XQuery / XSLT
Classification: Unclassified
Component: XSLT 3.0 (show other bugs)
Version: Last Call drafts
Hardware: PC All
: P2 normal
Target Milestone: ---
Assignee: Michael Kay
QA Contact: Mailing list for public feedback on specs from XSL and XML Query WGs
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-02-03 07:20 UTC by Michael Kay
Modified: 2014-05-15 14:00 UTC (History)
1 user (show)

See Also:


Attachments

Description Michael Kay 2014-02-03 07:20:26 UTC
Our rules for the scope of static variables turn out to have some unfortunate consequences. Consider the following:

<xsl:variable name="DEBUG" static="yes" select="false()"/>
<xsl:import href="common.xsl"/>
<xsl:variable name="DEBUG" static="yes" select="true()"/>
<xsl:import href="common.xsl"/>

where common.xsl includes something like

<xsl:assert .... use-when="$DEBUG"/>

The effect is that the use-when expressions in the two occurrences of common.xsl can have different values. This effectively means that we need to recompile common.xsl every time it appears, which is a significant performance regression from 2.0 for those stylesheets that contain multiple imports of the same module. There are some widely used stylesheets out there that import a common.xsl module 30 or 40 times, so the effect is significant.

(Note, this situation could arise even if we still had the rule that "imports must come first". Just replace the imports above by an include of a module that does nothing other than to import common.xsl).

I would like to suggest a different rule which avoids this problem but removes very little useful functionality.

We define an order of declarations in which, effectively, xsl:include and xsl:import are expanded inline. (This is an extension to the current "declaration order" that treats import the same way as include). Then for static variables, if multiple declarations of the same variable name are encountered, we use the FIRST one encountered, and use it consistently throughout the entire stylesheet (package).

This behaves in the same way as at present in that parent modules override their child modules in the import tree, but it works differently for sibling imports: it is now the first import that counts, rather than the last. I think that overriding declarations in preceding-sibling modules is relatively uncommon and not especially useful, so I think this is a small price to pay for the benefits that we get if a static variable has the same value throughout the compilation of a package.

The new rule applies only to static expressions (that is, use-when); variable references in dynamic expressions are unaffected.

The rule introduces an inconsistency between static and dynamic variable references; but the rules for these two cases are already inconsistent. And in one respect they become more consistent, in that it will now be true in both cases that a given variable has a single value throughout the package.
Comment 1 Michael Kay 2014-02-03 08:08:52 UTC
Note, the example was over-simplified. Having two declarations of DEBUG in the same module would be a static error. To make the example legal, one or both of these xsl:variable declarations has to be replaced by an xsl:import of a module that contains the declaration.
Comment 2 C. M. Sperberg-McQueen 2014-02-11 09:56:16 UTC
We discussed this issue during the Prague face to face.

There was some consensus that adopting a first-declaration-wins discipline would solve the problem originally raised.  Regarding multiple declarations we saw several options:

a) Multiple declarations of a static variable are always an error.

b) Multiple declarations are never an error.

c) The second declaration is an error if and only if it has the same or a higher import precedence.

d) The second declaration is an error if and only if it has the same or a higher import precedence and a different value (or an inconsistent value?).

e) The second declaration is an error if and only if it has a different value (independent of import precedence).

Option c) seemed problematic for stylesheets constructed with a configuration module declaring static variables which is multiply imported; option e) would raise an error when a parent module wants to override the setting in an imported module.

After discussion, the group converged on option d).  This leads to the question "what counts as the same or a consistent value?"  After further discussion, we concluded that the rules for identical value in F and O should suffice for this case.  (There were concerns about the rules for function values, but in a static context the only function values available are the built-ins, so identity of name really ought to suffice.)
Comment 3 Michael Kay 2014-03-24 16:07:16 UTC
I've implemented the decision as described.

The speculation about function values is well founded; it seems that according to the F&O definition, the two functions

function($x) { $x + 1 }

and

function($x) { $x + 2 }

are identical.

I will raise a bug on this against F+O. Meanwhile I will treat all functions as non-identical for safety.