This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 2789 - Substitutability of duration subtypes
Summary: Substitutability of duration subtypes
Alias: None
Product: XPath / XQuery / XSLT
Classification: Unclassified
Component: Functions and Operators 1.0 (show other bugs)
Version: Candidate Recommendation
Hardware: PC Windows XP
: P2 normal
Target Milestone: ---
Assignee: Ashok Malhotra
QA Contact: Mailing list for public feedback on specs from XSL and XML Query WGs
Depends on:
Reported: 2006-02-01 12:45 UTC by Michael Kay
Modified: 2006-03-04 00:24 UTC (History)
0 users

See Also:


Description Michael Kay 2006-02-01 12:45:24 UTC
Frans Englich posted as follows on the mulberry xsl-list yesterday:

Saxon 8.6 fails this expression with XPTY0004, "Cannot compare 
xdt:yearMonthDuration to xs:duration":

xdt:yearMonthDuration("P200Y2M") eq xs:duration("P200Y2M")

The XPath 2.0 book specifies these operators:

A eq B  xdt:yearMonthDuration     xdt:yearMonthDuration  
A eq B  xdt:dayTimeDuration  	  xdt:dayTimeDuration  
A eq B  xs:duration               xs:duration

It also says this:

Any operator listed in the operator mapping tables may be validly applied to 
an operand of type AT if the table calls for an operand of type ET and 
type-matches(ET, AT) is true (see 2.5.4 SequenceType Matching). For example, 
a table entry indicates that the gt operator may be applied to two xs:date 
operands, returning xs:boolean. Therefore, the gt operator may also be 
applied to two (possibly different) subtypes of xs:date, also returning 

Doesn't type-matches(xs:duration, xdt:yearMonthDuration) hold true? My point 
being that the expression should succeed because xdt:yearMonthDuration is a 
subtype of xs:duration and that the xs:duration-eq operator therefore can be 
applied. If that is the case, which I doubt, the eq/ne operators for the two 
XDT durations are redudant, since the xs:duration-eq/ne operators covers 

What clause in any of the specifications disallow the above operand 
combination? (and the others variations by the same principle)

I think Frans has a good point here. op:duration-equal is defined as

if (cast as xdt:yearMonthDuration ($arg1) eq
      cast as xdt:yearMonthDuration($arg2) 
      cast as xdt:dayTimeDuration($arg1) eq 
      cast as xdt:dayTimeDuration ($arg2)) return fn:true()
  else return fn:false()

and this produces the correct result for any combination of duration,
dayTimeDuration, and yearMonthDuration.

So I think we should remove the four lines in the operator mapping table that
define eq and ne operations between subtypes of duration, and the corresponding
functions op:dayTimeDuration-equal and op:yearMonthDuration-equal.

Michael Kay
Comment 1 Frans Englich 2006-02-01 13:53:39 UTC
I thought some more about it, and the current situation is a bit of a can of   
worms, I'd say. Consider the following expression:   
From what I can tell, the validity of this expression depends on whether the   
dynamic types(xdt:dayTimeDuration/xdt:yearMonthDuration) or the static   
types(xs:duration/xs:duration) are used for the operator lookup. Perhaps,  
behavior could in practice become implementation dependent, considering the  
freedom implementations have in handling the types of values(subtype  
substitution, for example). The essence seems to be that in the case of the  
duration operators one can't rely on the very primitive base type(which  
one can in all other cases), but that a sub-type/dynamic type might be of  
importance. But yes, the solution Michael proposed seems to solve all this.  
Also, the pseudo function in op:duration-equal can be simplified into:   
return cast as xdt:yearMonthDuration($arg1) eq   
       cast as xdt:yearMonthDuration($arg2)    
       cast as xdt:dayTimeDuration($arg1) eq    
       cast as xdt:dayTimeDuration($arg2)  
It is less code(the if-expression was removed), but, of course, that doesn't  
necessarily mean readability is improved.  
Comment 2 Michael Rys 2006-02-01 15:05:55 UTC
In the expression


both the static and dynamic type of the two values will be xs:duration (the 
cast changes the dynamic type as well). So I do not see your problem....
Comment 3 Frans Englich 2006-02-01 15:58:26 UTC
Yes Rys, I think you are right.    
I don't know your reasoning, but from what I can tell a cast expression can    
return a value whose type is more specific than the static one(from the 
definition of dynamic type). However, the reason why that doesn't apply to this 
particular case of xs:duration/xdt:dayTimeDuration is that the relevant 
sections in F&O special case those; xdt:dayTimeDuration isn't treated as a 
xs:duration value.    
Curiosity: my conclusion is that the expression in comment #1 triggers a   
bug in Saxon, but when Saxon implements what likely is the result of this   
report(the eq ops for xdt:durations are removed) the bug will go away.   
Comment 4 Michael Kay 2006-02-01 18:05:49 UTC
The Saxon problem is off-topic for this list, but is now fixed.

Michael Kay
Comment 5 Michael Rys 2006-02-01 18:47:00 UTC
"I don't know your reasoning, but from what I can tell a cast expression can 
return a value whose type is more specific than the static one(from the 
definition of dynamic type)."

Sorry, but a cast cannot return a more specific dynamic type than the static 
type. Casting is actually changing the dynamic type and transforms the value 
from one type's value space to another type's value space.

"treat as" does not change the dynamic type...
Comment 6 Michael Kay 2006-02-01 19:17:43 UTC
In discussion it emerged (i.e., Mary Holstege noticed!) that we can't simply get
rid of op:yearMonthDuration-equal and op:dayTimeDuration-equal because the
definition of op:duration-equal invokes these functions implicitly. On the other
hand, the definition of equality on the two subtypes is not saying anything very
profound. So we probably need a revised definition of op:duration-equal, in
which case the other two functions can be dropped. I was actioned to write a
concrete proposal.
Comment 7 Michael Kay 2006-02-01 19:36:32 UTC
"Sorry, but a cast cannot return a more specific dynamic type than the static 

I've asked myself this question a number of times, and have come to the
conclusion that the result of a cast *can* be a subtype of the type requested. I
think it is a general property of our processing model (see that
expressions can return a value whose dynamic type is a subtype of the type
implied by the static signature. For example the specification requires that the
result of 1+1 is an xs:integer, and an implementation that returns a value of
type xs:short conforms to this requirement because every xs:short is an
xs:integer. By the same reasoning it is acceptable for xs:int(1+1) to return a
value whose most specific type is xs:short. 

In Saxon, casting to a supertype is generally a no-op, and I believe this is
Comment 8 Michael Rys 2006-02-01 19:45:31 UTC
I agree with your interpretation for arithmetic. But this is incorrect when 
casting. Casting per definition needs to change both the static and dynamic 
type. Casting up the type hierarchy is only a noop regarding the value 
transformation, but it has to change the type annotation...

Best regards
Comment 9 Colin Adams 2006-02-03 07:14:41 UTC
Note that 365D is not necessarilly equal to 1Y. Isn't this why we have two
distinct, non-overlapping sub-types of xs:duration in the first place?
Comment 10 Michael Kay 2006-02-17 19:34:13 UTC
The discussion on this bug has explored some interesting side alleys, but I'm
now trying to fulfil action A-288-29 by proposing changes for how durations
should be compared for equality (that is, eq and ne).

1. In the XPath/XQuery book, appendix B.2, delete the lines

A eq B 	xdt:yearMonthDuration 	xdt:yearMonthDuration 	
A eq B 	xdt:dayTimeDuration 	xdt:dayTimeDuration 
A ne B 	xdt:yearMonthDuration 	xdt:yearMonthDuration 	
A ne B 	xdt:dayTimeDuration 	xdt:dayTimeDuration	

2. In F+O delete sections 10.4.1 (op:yearMonthDuration-equal) and 10.4.4

3. To 10.4.7 op:duration-equal add after the second paragraph:

Note that this function (like any other) may be applied to arguments that are
derived from the types given in the function signature, including the two
subtypes xdt:dayTimeDuration and xdt:yearMonthDuration. With the exception of
the zero-length duration, no instance of xdt:dayTimeDuration will ever be equal
to an instance of xdt:yearMonthDuration.

Change the definition of the semantics of the function to read:

The semantics of the function are defined by the following expression:

xdt:yearMonthDuration($arg1) div xdt:yearMonthDuration('P1M')
xdt:yearMonthDuration($arg2) div xdt:yearMonthDuration('P1M')
xdt:dayTimeDuration($arg1) div xdt:dayTimeDuration('PT1S')
xdt:dayTimeDuration($arg2) div xdt:dayTimeDuration('PT1S')

that is, the months and seconds components of the two durations are each equal.

To the examples, add

op:duration-equal(xdt:yearMonthDuration('P0Y'), xdt:dayTimeDuration('PT0D'))
returns true

op:duration-equal(xdt:yearMonthDuration('P1Y'), xdt:dayTimeDuration('PT365D'))
returns false
Comment 11 Michael Kay 2006-02-19 13:48:43 UTC
A minor addition to the proposal in comment #10:

Take the existing examples in sections 10.4.1 (op:yearMonthDuration-equal) and
10.4.4 (op:dayTimeDuration-equal) and add them to the revised section 10.4.7

Michael Kay
Comment 12 Michael Kay 2006-02-19 13:55:29 UTC
Ignore comment #11. There are no existing examples in sections 10.4.1
(op:yearMonthDuration-equal) and 10.4.4 (op:dayTimeDuration-equal). Instead,
create some new examples:

op:duration-equal(xdt:yearMonthDuration('P2Y'), xdt:yearMonthDuration('P24M'))
returns true

op:duration-equal(xdt:dayTimeDuration('P10D'), xdt:dayTimeDuration('PT240H'))
returns true

op:duration-equal(xs:duration('P2Y0M0DT0H0M0S'), xdt:yearMonthDuration('P24M'))
returns true

op:duration-equal(xs:duration('P0Y0M10D'), xdt:dayTimeDuration('PT240H'))
returns true

Michael Kay
Comment 13 Jim Melton 2006-02-21 16:38:47 UTC
We accepted the solution in comment #10 and #12.