RE: last() with grounded consuming sequences

> 
> 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