-
Notifications
You must be signed in to change notification settings - Fork 15
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
Dynamic Function Calls: Processing Empty Sequences #707
Comments
There's a counter-argument, which is that propagating empty sequences is one of the things that makes XPath/XSLT very hard to debug: you get a select expression wrong, and the result is empty output, not an error. I've been thinking recently about adding <xsl:apply-templates select="checked{.//item}"/> would throw an error if there are no items. The mode of execution would propagate downwards, so
Hope this isn't hijacking your thread: my point is, if the behaviour were switchable like this, I would find your proposal much more appealing. |
Yes, checks can be helpful. We’ve done things like this in the past: let $traverse := function($root, $steps) {
fold-left($steps, $root, function($nodes, $step) {
let $result := $nodes/*[name() = $step]
return if ($result) then $result else error((), $step || ' not found')
})
}
return $traverse(<xml><a><b/></a></xml>, ('a', 'b')) …or, more generally: let $traverse := fn($root, $steps) {
fold-left($steps, $root, fn($nodes, $step) {
$step($nodes) otherwise error()
})
}
return $traverse(<xml><a><b/></a></xml>, (fn { a }, fn { b })) The Besides paths, would you also like to cover all other XPath functions and operations that accept empty sequences (arithmetic expressions, value comparisons, XPath 1.0 functions)? |
PS: What would be the difference between the two approaches? <xsl:apply-templates select="checked{ a/b }"/>
<xsl:apply-templates select="a/b otherwise error()"/> I assume that |
I think the key thing is to catch "selection expressions" that select nothing. That includes axis steps, filter expressions, and map lookups. The detailed list would need to be carefully worked out. Other things like value comparisons generally only return () if one of their operands returns (), and the aim is to catch the emptiness as early as possible so you can work out which selection has "failed". |
As regards alternatives such as "otherwise" or "treat as item()+", I think the key difference is that |
Let's not forget the proposal for the capability to add a default key-value to maps: #105 We can conveniently return the default value of $75 for a night's hotel price for any night after the third one: let $price-for-night := map {
1 : 100,
2 : 90,
3 : 80
'\' : 75
}
return
$price-for-night(10) produces #105 actually subsumes this proposal, because if we want the empty sequence to be returned, we can simple express this as: let $price-for-night := map {
1 : 100,
2 : 90,
3 : 80
'\' : ()
}
return
$price-for-night(10) It is easy to see that this current proposal has a few shortcomings (the last one critical):
Lesson learned: It is good to know and remember that the empty sequence |
True; if you have full control over your input data, things look different. My proposal has mostly driven by users who work with external data (JSON, CSV, YAML, MD) converted to maps/arrays, and who tend to use parentheses instead of the lookup operator. Another showstopper for this in practice is the incompatibility between maps and arrays. With |
Most importantly, the 3rd issue from my comment is definitely a show-stopper:
|
This is just a kind of data validation. This can be implemented as a simple decorator (#106) and can provide the necessary level of flexibility - no need for "special modes". Actually, this is a decorator factory, that is a decorator that accepts its own parameters besides the function (or map or array) that it decorates, and produces a parameter-less decorator.
produces a decorator that evaluates the function passed to it, and if the result of this evaluation is empty (whatever we define this value to be, or maybe pass it as another parameter to the decorator-factory) it raises an error. And:
produces a no-op (or identity) decorator, that evaluates the function and returns its result. |
Apart from new constructs/expressions, we could also use annotations or pragmas. – But that's out of scope, it might be better to create a new issue for this discussion. |
As I understand it, the decorator concept applies only to functions, whereas we are concerned here with expressions such as It's true that we could use pragma syntax for this; although it's currently XQuery-only. |
Isn't it true that:
is equivalent to:
We can decorate any such function, which means any such expression. Also, let us not forget that both maps and arrays are functions, therefore we can decorate both maps and arrays. |
@dnovatchev @michaelhkay I have created a new issue which we could use for further discussion on (un)checked evaluation: #709 |
I propose to close this; there hasn’t been much applause (and one can still use the lookup operator as a lax fallback). |
The CG agreed to close this issue without action meeting 59. |
A fundamental – and brilliant – property of XPath is that many operations tolerate empty sequences: Instead of throwing an error, the empty result is passed on unchanged to the next operation. While this is unrewardingly confusing for binary operations (
() + 1
,() eq 5
), it’s wonderful for pipelines:As far as I can judge, it would be a very simple and user-friendly addition if we extended dynamic function calls to return an empty sequence (instead of raising an error) if the base expression is an empty sequence. This way, the following expressions would all run through:
Many people use parentheses instead of the lookup operator for accessing maps & arrays, and the proposed change would make the syntax more interchangeable. I believe it would also be useful for function items in general.
The text was updated successfully, but these errors were encountered: