Apologies for not posting this to dev.saxonica.com/community, but the site
appears to be down this evening.
Am I mistaken, or should it be possible to use an "as" clause to constrain the
type of a command-line-supplied XSLT program parameter? I've just tried to
write
<xsl:param name="level" as="xs:nonNegativeInteger" select="xs:nonNegativeInteger(1)"/>
as a top-level statement instead of the usual
<xsl:param name="level" select="1"/>
in the hope of leveraging a run-time "as" check in order to simplify
<xsl:template match="/">
<xsl:choose>
<xsl:when test="$level castable as xs:nonNegativeInteger" ?<br="">... do the desired thing ... </xsl:when>
<xsl:otherwise>
...complain...
</xsl:otherwise>
<xsl:choose>
</xsl:template>
to
<xsl:template match="/">
.... do the desired thing ...
</xsl:template>
Basically, this doesn't work. If (e.g.) I set "level" to "one", the run-time
system fails to fail when my program starts. Instead, it generates a series of
complaints (recoverable errors) about "one" not being convertable to an
integer.
One other point about this logic puzzles me, as well. Why is it necessary to
explicitly cast 1 as a datum of type xs:nonNegativeInteger when you specify an
"as" clause of "xs:nonNegativeInteger"? This is one place where I'd want a
language to do a coercion on my behalf, since there's no possible loss of
precision that results from "downcasting" xs:integer(1) to
xs:nonNegativeInteger(1).
-- Phil
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Sorry for the prolonged downtime on the dev.saxonica.com site. We've rebuilt
the server after a security breach but restoring the data has been taking
longer than expected.
I'm afraid the use of types like xs:nonNegativeInteger isn't very satisfactory
in XSLT/XQuery. During the development of the language, I argued in favour of
these being treated like predicates ("check that the integer is non-negative")
but those who know a lot more about the theory of programming language type
systems than I do, people like Phil Wadler, were very insistent that the type
should be a label associated with the instance - "named typing" versus
"structural typing" - so an integer is only a nonNegativeInteger if it is
labelled as such. I agree with you that automatic downcasting of an xs:integer
to an xs:nonNegativeInteger would make much more sense here. The one time you
do get automatic casting, however, is if you supply an untypedAtomic value.
However, on your first point, it's not obvious to me why the errors ("one" not
being convertible) are treated as recoverable. Perhaps it's because you are
using the value in a pattern - all errors during pattern matching are
recoverable. Otherwise, I would need to see more detail on exactly what you
are doing.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks for replying as well as for the news about dev.saxonica.com.
I was indeed using $level in a pattern, as part of a "match" attribute that
counts a node's ancestors. It's part of a simple code that I was creating for
a senior-level class on XML: a program that reverses elements at level n of a
document for a user-specified n. The application will still make for an
interesting discussion, now that I understand this point about recovering from
type failures in patterns: the failure to enforce the "as" condition on $level
on program entry would seem to be consistent with lazy evaluation.
As for the point about typing, the comment about limiting type inference to
what's provided by named typing is indeed helpful: thank you. Wadler's point,
I would guess, would be that trying to accommodate special-case downcasting in
a language that's already as rich as XSLT 2.0 would make the language that
much harder to implement. Something else to tell my students...
Appreciatively,
-- Phil
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Apologies for not posting this to dev.saxonica.com/community, but the site
appears to be down this evening.
Am I mistaken, or should it be possible to use an "as" clause to constrain the
type of a command-line-supplied XSLT program parameter? I've just tried to
write
<xsl:param name="level" as="xs:nonNegativeInteger" select="xs:nonNegativeInteger(1)"/>
as a top-level statement instead of the usual
<xsl:param name="level" select="1"/>
in the hope of leveraging a run-time "as" check in order to simplify
<xsl:template match="/">
<xsl:choose>
<xsl:when test="$level castable as xs:nonNegativeInteger" ?<br="">... do the desired thing ...
</xsl:when>
<xsl:otherwise>
...complain...
</xsl:otherwise>
<xsl:choose>
</xsl:template>
to
<xsl:template match="/">
.... do the desired thing ...
</xsl:template>
Basically, this doesn't work. If (e.g.) I set "level" to "one", the run-time
system fails to fail when my program starts. Instead, it generates a series of
complaints (recoverable errors) about "one" not being convertable to an
integer.
One other point about this logic puzzles me, as well. Why is it necessary to
explicitly cast 1 as a datum of type xs:nonNegativeInteger when you specify an
"as" clause of "xs:nonNegativeInteger"? This is one place where I'd want a
language to do a coercion on my behalf, since there's no possible loss of
precision that results from "downcasting" xs:integer(1) to
xs:nonNegativeInteger(1).
-- Phil
Sorry for the prolonged downtime on the dev.saxonica.com site. We've rebuilt
the server after a security breach but restoring the data has been taking
longer than expected.
I'm afraid the use of types like xs:nonNegativeInteger isn't very satisfactory
in XSLT/XQuery. During the development of the language, I argued in favour of
these being treated like predicates ("check that the integer is non-negative")
but those who know a lot more about the theory of programming language type
systems than I do, people like Phil Wadler, were very insistent that the type
should be a label associated with the instance - "named typing" versus
"structural typing" - so an integer is only a nonNegativeInteger if it is
labelled as such. I agree with you that automatic downcasting of an xs:integer
to an xs:nonNegativeInteger would make much more sense here. The one time you
do get automatic casting, however, is if you supply an untypedAtomic value.
However, on your first point, it's not obvious to me why the errors ("one" not
being convertible) are treated as recoverable. Perhaps it's because you are
using the value in a pattern - all errors during pattern matching are
recoverable. Otherwise, I would need to see more detail on exactly what you
are doing.
Thanks for replying as well as for the news about dev.saxonica.com.
I was indeed using $level in a pattern, as part of a "match" attribute that
counts a node's ancestors. It's part of a simple code that I was creating for
a senior-level class on XML: a program that reverses elements at level n of a
document for a user-specified n. The application will still make for an
interesting discussion, now that I understand this point about recovering from
type failures in patterns: the failure to enforce the "as" condition on $level
on program entry would seem to be consistent with lazy evaluation.
As for the point about typing, the comment about limiting type inference to
what's provided by named typing is indeed helpful: thank you. Wadler's point,
I would guess, would be that trying to accommodate special-case downcasting in
a language that's already as rich as XSLT 2.0 would make the language that
much harder to implement. Something else to tell my students...
Appreciatively,
-- Phil