This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.
This query can also return the empty sequence. In this context e[928] is effectively (fn:error('err:XPDY0002'))[928] which can be evaluated through type analysis to be the empty sequence. K2-FunctionProlog-14 has a similar problem. (:*******************************************************:) (: Test: K2-Steps-2 :) (: Written by: Frans Englich :) (: Date: 2007-11-22T11:31:21+01:00 :) (: Purpose: A numeric predicate combined with a name test inside a function. :) (:*******************************************************:) declare function local:myFunc() { e[928] }; local:myFunc()
But isn't this extremely counter intuitive? The user has done wrong: she's using an axis step inside a function. Instead of that it gets reported as an error, it evaluates to a perfectly valid result: an empty sequence. It's not helpful, in my opinion. What says an expression that happens to contain a dynamic error, can be rewritten to a call to fn:error? I'd say e[928] isn't effectively equal to (fn:error('err:XPDY0002'))[928] because in the latter case it has the static type none, which the former doesn't have.
Refer to: http://www.w3.org/TR/xquery/#id-errors-and-opt "Consider an expression Q that has an operand (sub-expression) E. In general the value of E is a sequence. At an intermediate stage during evaluation of the sequence, some of its items will be known and others will be unknown. If, at such an intermediate stage of evaluation, a processor is able to establish that there are only two possible outcomes of evaluating Q, namely the value V or an error, then the processor may deliver the result V without evaluating further items in the operand E. For this purpose, two values are considered to represent the same outcome if their items are pairwise the same, where nodes are the same if they have the same identity, and values are the same if they are equal and have exactly the same type." I agree it isn't intuitive, but I'm sure it is correct. I rather wish the type of fn:error was, in Haskell style: empty-sequence() IO (indicating an expression with side effects) rather than none which I believe would help to get rid of these oddities (and clean up XQuery Update).
I can't see how that paragraph applies, I need further help with this! My understanding is that that paragraph says that an implementation can choose between delivering a sequence of items or an error, if both are the outcome of evaluating an expression. However in the case of: declare function local:myFunc() { e[928] }; local:myFunc() where does the empty sequence come from? Maybe one can infer it from the fn:error() function, but hasn't yet been clarified how that one enters the picture. I agree, the none type surely gives us a lot of trouble :}
The context item has static type 'none' because accessing it is equivalent to calling fn:error (whose return type is none). So we can rewrite the path expression $fs:dot/e as a call to fn:error. declare function local:myFunc() { (fn:error('err:XPDY0002'))[928] }; The quantifier of fn:error is 1, so we either have a sequence of one item or an error. But we're not interested in the first item, so there's no need to evaluate it to cause an error. We want item 928 - therefore we get the result as ().
"The context item has static type 'none' because accessing it is equivalent to calling fn:error (whose return type is none). So we can rewrite the path expression $fs:dot/e as a call to fn:error." So, if an expression yields an error, it's ok to rewrite it to fn:error? So for any expression that raise an expression one can potentially rewrite to fn:error and then proceed to reduce using the type none? I don't see how that holds. I'd say that just because an expression raise an error, doesn't make it ok to rewrite to function fn:error.
> I don't see how that holds. I'd say that just because an expression raise an > error, doesn't make it ok to rewrite to function fn:error. We only do this wtih dynamic errors. Why wouldn't this rewrite be valid? Could a user see a difference between an expression raising an error and a call to fn:error? Does anyone else have an opinion on this?
>So, if an expression yields an error, it's ok to rewrite it to fn:error? So for any expression that raise an expression one can potentially rewrite to fn:error and then proceed to reduce using the type none? It seems to me to be perfectly reasonable to rewrite the expression as fn:error() - but not reasonable to then do type inferencing on error() and further reduction that causes the error not to be raised! Frankly, I think that we haven't formalized error behaviour to the level where such rewrites are safe. I've found that it's generally better to infer a type of item()* for expressions known to throw an error - but that's in an optimistic environment, of course.
Consider: declare function local:something() as xs:integer { 1 } (local:something())[928] Do you think it is reasonable to return () here without evaluating the function? If we redefine the functions as: declare function local:something() as xs:integer { fn:error() } do you still think it reasonable? As I've said before, I think fn:error should have been treated in the way that exceptions are treated in Haskell, since the error is a side-effect, and the same goes for updating expressions. As I'm sure you are aware, the reason fn:error can't be treated as item()* is that static type checking would end up with type check errors all over the place. e.g. declare function local:maybe-error($arg as xs:boolean) as xs:integer { if ($arg) then fn:error() else 1 } With fn:error() as 'none', this type checks correctly. Were it item()*, the call to fn:error would cause a static type check error.
>do you still think it reasonable? I have found it necessary to be pragmatic with error situations: the criterion for what is reasonable is based on how helpful it is to the user. Failing to report a simple error that can be detected statically, and returning an empty sequence instead, does not seem helpful. I'm well aware that treating error() as item()* doesn't work in a static typing environment, but fortunately I don't have that problem. (Well, not fortunately, it was by deliberate choice...) But of course we're dealing with a test suite here, and it's testing for conformance not for usability. Unfortunately I don't think that static typing is spec'ed well enough to ensure interoperable results especially in error situations, so I personally think this is a losing battle. There's probably a chain of reasoning that says 42 is a valid answer to the query 2+2.
> But of course we're dealing with a test suite here, and it's testing for > conformance not for usability. You are right. So do you think it conformant behaviour?
>So do you think it conformant behaviour? I wouldn't dare to venture an opinion. With static typing, nothing (not even a failure to report a statically detectable error) would surprise me. But I think there comes a time when a test suite has to take a pragmatic view. The rules on errors and optimization license an implementation to throw an error for the query 2+2. I don't think that means the test suite should list this as an approved result. There comes a time when you have to report that you consider your result conformant even though it's not the expected result that was published.
For what it's worth I'm not convinced this is conformant behavior, but I think we can add a static typing query that follows the line of thinking of the static typing community. Tim, could you provide a query which unconditionally raise XPDY0002 for static typing implementations? Will "node-test", without quotes, do? I'll add that as a @static-name test.
Thanks Mike. fn:error really has caused us a lot of head scratching. On some days, I can convince myself that count(fn:error()) is 1. I don't like it. but I think it is correct. I may post a further question to clarify whether both: (1, fn:error())[1] and (fn:error(), 1)[2] can be conformantly executed without error.
Frans - we get this result whether we use static typing or not. The result isn't really resulting from type analysis as much from the rule quoted in Comment 2.
Is the [928] important? How about: declare function local:myFunc() { e[1] }; local:myFunc()
Added the query in comments #15 as static typing queries for the two tests in question. Feel free to verify, and close if everything looks ok.
Frans - I've looked a little further into why we are returning empty sequence here. In K2-Steps-2, e[928] ends up being transformed into fs:item-at($fs:seq, 928) (see Bug 4841 for details of fs:item-at). The type checking rule is: statEnv |- QName of func expands to (FS-URI,"item-at") statEnv |- Expr1 : Type1 -------------------------------------------------------- statEnv |- QName(Expr1, Expr2) : prime(Type1) ? which here is fs:item-at( something of type none, 928) prime(none) = none none? = empty Therefore it is definitely correct to say that e[928] is empty sequence.. A static typing implementation would be required to raise XPST0005 here (that's an expected result), but any implementation is free to return () here. Would this persuade you to add this as a possible result?
In Bug 5810, Michael Dyck has confirmed that fs:item-at(fn:error(), Expr) can be rewritten as the empty sequence by virtual of its static type. "I don't see how that holds. I'd say that just because an expression raise an error, doesn't make it ok to rewrite to function fn:error." This can all be proved without actually performing a rewrite to fn:error. $fs:dot has type none (because it is an error). From FS. statEnv |- axis Axis of none : none So $fs:dot/child::e is also of type none. fs:item-at( $fs:dot/child::e (of type none), 928) is empty Any expression of type empty can be rewritten as the empty sequence.
>Any expression of type empty can be rewritten as the empty sequence. Section 4 states: During static analysis, it is a type error for an expression to have the empty type, except for the following expressions and function calls: * Empty parentheses (), which denote the empty sequence. * The fn:data function and all functions in the fs namespace applied to empty parentheses (). * Any function which returns the empty type. If this rule is to make sense at all, then it must surely be applied before doing any rewrites. You can't rewrite an expression as "()" as a way of getting around this rule.
This is the paragraph which gives rise to XPST0005 - an error distinct to the static typing feature (2.3.1 Kinds of Errors, paragraph 7). If the static typing feature isn't in effect, an implementation isn't required to throw this error. Incidentally, many static typing implementations appear to ignore, apply selectively (e.g. only in path expressions) or allow this error to be switched off. If the static typing feature is switched off, the extent to which the static typing rules are used during query analysis is not prescribed by the standard. I'm specifically concerned here with running the tests with static typing feature switched off. The test case already correctly lists XPST0005 as a valid result.
Regarding: "fs:dot has type none (because it is an error)". Could you elaborate on how the spec backs this up? Here's how I understand it: if fs:dot has type none because it raises an error(the context is undefined), then that means XPDY0002 never appears in the cases where subsequent code starts inferring based on the none type. And can the same kind of logic be applied to other expressions? E.g 1) it's statically detected an expression will raise an error; 2) the expression's type changes to none(which I don't understand why); 3) inference goes to work and the error is not reported.
Created attachment 561 [details] Tests involving fn:error() Attached are a set of queries which I believe show how fn:error() can be optimized away through static analysis of the queries.
> Regarding: "fs:dot has type none (because it is an error)". Could you elaborate > on how the spec backs this up? I can only state the equivalence of a dynmaic error (namely accessing an undefined context item) and a call to fn:error. This is backed up by Formal Semantics, which shows how the dynamic error raised by the "treat as" expression is normalized to a call to fn:error. [Expr treat as SequenceType]Expr == typeswitch ([ Expr ]Expr) case $fs:new as SequenceType return $fs:new default $fs:new return fn:error()
I've just had a play with Saxon to see what it does here. For the original query: declare function local:myFunc() { e[928] }; local:myFunc() it throws an error, but it returns empty sequence for: declare function local:myFunc() { e[false()] }; local:myFunc() Regarding Comment #1, in both these queries "The user has done wrong: she's using an axis step inside a function."
I think we're in the realms of usability rather than conformance here: it's going to be very hard to formalize the rules on error handling to ensure all products are compatible in such cases. But I think the test suite needs to make assumptions about what's reasonable: for example it can legitimately assume that the implementation's limit on the length of strings will be greater than 10, and I don't think the expected results should be changed because some implementation blows its limits. I think that the rewrite from e[928] to error()[928] to () is simply poor design from a usability point of view. Once you've decided there is an error here you should take care to ensure the user knows about it. The difference with e[false()] is that the sequence of rewrites never went via error() to something else. Yes, arguably the processor should have tried harder to check for error conditions before doing the rewrite, but it's hard to argue against doing context-independent rewrites before starting to look at the context.
We're following the rules for static typing here, which (like it or not) make it quite clear that: e[1] is of type empty if the context item's value is undefined. This isn't really comparable to differences due to implementation limits. As an aside, I rather think the usability problem here is that this accessing of the undefined context item in a function body is considered to be a dynamic error rather than a static error.
Created attachment 562 [details] Tests involving fn:error() Attached is an updated set of 35 queries where a call to fn:error() can be optimized away through static analysis of the queries.
"The difference with e[false()] is that the sequence of rewrites never went via error() to something else. Yes, arguably the processor should have tried harder to check for error conditions before doing the rewrite, but it's hard to argue against doing context-independent rewrites before starting to look at the context." For the query: error()[928] we normalize to: let $fs:seq_7 as item()* := fn:error() return fs:item-at($fs:seq_7, 928) We then perform static type analysis which spots that the expression has type empty. In the original query, we necessarily look at the static context to get the context item's type. Once that's done, the only (context-independent) rewrite is to replace an expression with type empty with (). I agree that it is hard for a processor to check for error conditions, since the type system does not capture a difference between a function which, say, returns an integer from one which may return an integer or raise an error.
Other queries which can return () or raise XPST0005 are: K2-Steps-3 K2-FilterExpr-8 K-SeqRemoveFunc-13 (reported in Bug 5991)
Hi, There is unfortunately some administrative details to my W3C membership to attend to, which has as result that I can't do W3C work until end of august(and let's hope it doesn't stretch out more than that). As a result, progress on this report as well as others assigned to me/XQTS will have to wait.
In K2-Steps-2, the query e[928] makes a reference of a context item, however, the input variable binding is $input-context, not context item, therefore, this shall result as XPDY0002 errors. Furthermore, xquery spec allows implementation to do static analysis and catch and raise such error statically. However, using static anlaysis to infer types and compute results while there are errors detected in previous steps are not very sounded and not very well defined (at least not covered by the xquery spec or formal semantic spec). So per working group discussion, we close this bug as resolved.
Based on the solution Zhen provided in comment 31, we're marking this bug RESOLVED/WONTFIX. If this resolution is satisfactory, please mark the bug CLOSED.