- From: Abel Braaksma <abel.braaksma@xs4all.nl>
- Date: Mon, 19 Oct 2015 14:33:07 +0200
- To: "Public XSLWG" <public-xsl-wg@w3.org>
> > I’ve been writing up the consensus we reached on use of last() with > grounded consuming sequences (i.e. that it may cause buffering), and I > wondered if a different solution might be better, along the following lines: > > * In any focus-changing construct (§19.3), if the controlling operand is > [grounded and] consuming, then the focus that is established for the > controlled operands has an absent context size. When last() is evaluated with > such a focus, it throws XPDY0002. (There’s a discussion going on in XQ about > whether to turn this into a type error or static error; pragmatically, we could > simply say that if the error can be detected statically then it can be reported > statically.) > > For example: > > <xsl:for-each select=“/*/transaction/copy-of()”> > <xsl:value-of select=“last()”/> > </xsl:for-each> > > throws an error I'm intrigued by the idea. The combination of grounding *and* consuming means it can only ever happen if at least part of the expression is bound to a streamed node. This allows your grounded-but-motionless workaround where the result is first put in a variable. Obviously, this puts some strains on implementations that we previously didn't have: 1) grounded seqtors or constructs were "free havens", where any expression was allowed, now not anymore 2) variable bindings can, under certain circumstances, *not* be (aggressively) inlined anymore 3) this error may happen in the most peculiar depths of nested, recursive, repeating templates, which may be hard to explain to a user *why* he is not free in a non-streaming template / for-each / xsl:iterate / xpath expression etc Another, remaining question is: what happens in match="bar[last()]" in a non-streaming template, where the input is a result of a select expression using copy-of()? Current rules would dictate that, because it raises an error, it will never match. Is that an acceptable behavior? > > It would be nice to do this without also preventing (position() = last()), but > attempting that would make the idea too complicated. > > Sorry, I know it’s late in the day to be raising this idea. Yes, it would be nice to allow this. But since these grounded-consuming expressions can also end up in non-streamed xsl:template bodies, allowing "position() = last()" requires analyzing all non-streaming modes as well, which is a statical analysis nightmare. I could repeat my idea of wrapping this in a single construct (xsl:on-last, or fn:is-last()), but I believe you were little enthusiastic about that in an earlier discussion (for obvious reasons, though a single call / construct is easier to track than a combination of function calls). Either way, we keep having the issue that in our "safe haven" of non-streaming constructs (those that have streamable="no"), we can now end up having an error that is caused by, ahum, streaming! > > The basic difference with this proposal is that using last() in such > circumstances will usually give you either a static error or a dynamic error > when processing the first item, rather than an “out-of-memory” error when > the sequence becomes too big to handle. > This seems a good suggestion all in all, but I would like to add that our previous conclusion on the same, using dynamic errors caused by streaming, should be avoided at all cost. I have, in principal, no objections to this renewed effort to try to find a more suitable, and kinder-to-the-user solution. Cheers, Abel
Received on Monday, 19 October 2015 12:33:43 UTC