This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.
We've been looking at static typing in the new functx tests, and have come across some queries which we are unable to rewrite so they type check, for example: declare function functx:value-except ( $arg1 as xs:anyAtomicType* , $arg2 as xs:anyAtomicType* ) as xs:anyAtomicType* { distinct-values($arg1[not(.=$arg2)]) } ; because fs:equal is not defined for all pairs of atomic types in xs:anyAtomicType an XPTY0004 is thrown. Obviously, separate value-except-type functions could be defined for arguments of each atomic type. But we can't think of any other way to rewrite such a function to type check. We propose two options to "fix" this problem. Option 1 -------- Recall the general comparisons expand (roughly) out to to the form: some $x in $arg1 satisfies some $y in $arg2 satisfies $x op $y So currently the queries (1, "foo") = "foo" and ("foo", 1) = "foo" may return true or XPTY0004, depending on the order in which the implementation happens to process the query. We'd like to propose that if the value comparison used in the expansion of the general comparison is not defined for the input types, then the result is false. Thus (1, "foo") = "bar" would return false. Option 2 -------- Add generics. declare function functx:value-except ( $arg1 as type(T) <: xs:anyAtomicType* , $arg2 as T ) as T { distinct-values($arg1[not(.=$arg2)]) } ; This of course would open up a need for a whole host of type-describing syntax, e.g. to specify subtype releationships, type unions etc. Option 3 -------- We could fix this query by using XQuery 1.1 try/catch. ".=$arg2" would have to be expanded out manually to "some" expressions with a try/catch to return "false" when the XPST0004 is raised. This would be rather clumsy. Option 4 -------- Define union, except, intersect functions/operators which work nicely with xs:anyAtomicType* input. Obviously this doesn't fix the general case. Our guess is that option 1 will make a wider variety of queries run in static typing mode, but introducing a breaking change with XQuery 1.0 might be unacceptable. Option 2 might be nice but might require a fair amount of work by the Working Group.
Presumably the issue also affects our own version of this function in http://www.w3.org/TR/xpath-functions/#value-except I've often argued that a=b should return false if a and b are of incomparable types, but I've always lost the argument to those who prefer the diagnostic power of raising an error. There are arguments both ways. A possible circumvention is to use one of the functions that does allow comparison of incomparables, for example index-of(), distinct-values(), or deep-equal(). If you don't want (a eq b) to fail, you can always write it as deep-equal(a, b).
(In reply to comment #0) > > Option 3 > -------- > > We could fix this query by using XQuery 1.1 try/catch. > > ".=$arg2" would have to be expanded out manually to "some" expressions > with a try/catch to return "false" when the XPST0004 is raised. > > This would be rather clumsy. I don't understand why you'd need to expand to 'some' expressions. Why not just replace .=$arg2 with try { .=$arg2 } catch err:XPTY0004 { false() } Or, for better encapsulation, replace it with my-equal(., $arg2) where 'my-equal' has the semantics that Option 1 would give to '=': declare function my-equal(...) as boolean() { try { $arg1 = $arg2 } catch err:XPTY0004 { false() } }
Haskell has type classes, described at http://www.haskell.org/tutorial/classes.html which seem like a very well designed way of describing the sort of constraints on types suggested by Option 2. This might be a useful addition to XQuery. As an off-topic aside, I'm personally a bit wary of try ... catch. I've got a horrible feeling I'm turning into a functional purist. Even element constructors make me feel queazy :)
At today's Working Group meeting, Nick Jones (the original poster) reviewed this bug, and said that try/catch allowed an adequate solution to the problem. Therefore, I am marking this bug Resolved-Fixed, and also Closed.