I noticed subtle differences how XQuery implementations handle (sub-)types. Especially, handling of literal numbers as input to functions that have the accepted input type declared. I naively thought any number literal that is castable to that specific numeric type would be accepted.
declare function local:any ($n as xs:anyAtomic) { $n };
declare function local:decimal ($n as xs:decimal) { $n };
declare function local:integer ($n as xs:integer) { $n };
declare function local:pos-int ($n as xs:positiveInteger) { $n };
local:any(1), (: works :)
local:decimal(1), (: works :)
local:integer(1), (: works :)
local:pos-int(1) (: throws in all tested implementations :)
exist-db allows xs:long
,xs:int
, ... Saxon does not.
I could not find any reason for that behaviour in the Xquery Spec 2.5.5 SequenceType Matching nor Xpath functions spec 1.6.3 Atomic Type Hierarchy
Could someone here shed some light on why Saxon 9.3.1 HE, BaseX 9.3.1 [Standalone] and eXist 5.3.0-SNAPSHOT behave like this?
Did I just miss the part in the spec where it is defined that a literal 1
is cast to xs:integer?
xs:decimal as the topmost type would have made more sense, but if one subtype is allowed why not go all the way?
I think the spec in this area is very unfortunate, but it is clear: a value is an
xs:positiveInteger
only if it is labelled as such, not simply because it is (a) an integer and (b) positive. There were long discussions about this in the XQuery Working Group, involving some eminent experts on programming language type systems (like Phil Wadler), and that's the decision that was made. I didn't like it myself.Where does the spec say this? The definitions in the XDM spec are a good start:
https://www.w3.org/TR/xpath-datamodel-31/#xs-types
Then §3.1.1 in the XQuery spec talks about numeric literals:
§3.18.1 gives the rules for the "instance of" operator:
and §2.5.5.2 gives the relevant rule for SequenceType matching:
Taken together, the effect is that the expression
3 instance of xs:positiveInteger
returns false (becausexs:integer
is not derived fromxs:positiveinteger
).Finally, when the expected type of a function argument is
xs:positiveInteger
, and the function call supplies the value 3, then the function conversion rules in §3.1.5.2 come into play. These allow various conversions from the supplied value to the required type, but "down-casting" from xs:integer to xs:positiveInteger is not one of them. So it's an error:As I say, I don't like the rules and have tried on numerous occasions to get them changed. But they are clear, and any product that doesn't follow them is non-conformant.