Discussion:
What is the best way to cast integer to string in XSLT2?
Dimitre Novatchev
2003-05-11 11:06:32 UTC
Permalink
Hi Mike and Jeni,

With Saxon 7.5 I'm getting an error on the following:

<xsl:value-of select="concat(position(), '. ', ., '&#xA;')"/>

"Type error in first argument of call to concat():
Required type is xs:string; supplied value has type xs:integer"

1. Why doesn't the XSLT processor perform an implicit cast from integer to
string? This is quite natural, as any atomic type has a string
representation and can be converted to string.

2. My current solution is to use

string(position())


Is this the best/recommended solution?


Thanks in advance,


=====
Cheers,

Dimitre Novatchev.
http://fxsl.sourceforge.net/ -- the home of FXSL




XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Andrew Watt
2003-05-11 11:37:49 UTC
Permalink
Post by Dimitre Novatchev
Hi Mike and Jeni,
<xsl:value-of select="concat(position(), '. ', ., '&#xA;')"/>
Required type is xs:string; supplied value has type xs:integer"
1. Why doesn't the XSLT processor perform an implicit cast from integer to
string? This is quite natural, as any atomic type has a string
representation and can be converted to string.
Hi Dimitre,

Here is my interpretation.

The position() functions returns an xsd:integer, as the error message
indicates. The concat() function takes only xsd:string arguments. Since the
first argument you are supplying to concat() is not an xsd:string a type
mismatch occurs and you get the error message that you report.

Why wasn't it automatically cast to xsd:string? Automatic casting in XSLT
2.0 / XPath 2.0, as I understand it, will only take place when the data is
untyped. For example, if you supplied as an argument to concat() untyped
data such as the content of <someElement>Blah blah</someElement> the
content would be treated internally as xdt:anyAtomicType. The XSLT
processor *would* automatically cast xdt:anyAtomicType to xsd:string if you
supply that to concat() as an argument, but won't (without explicitly being
told) cast an xsd:integer to an xsd:string.
Post by Dimitre Novatchev
2. My current solution is to use
string(position())
Is this the best/recommended solution?
It's what I would do.

I hope that helps.

Andrew Watt



XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Jeni Tennison
2003-05-11 13:41:33 UTC
Permalink
Hi Dimitre,
Post by Dimitre Novatchev
<xsl:value-of select="concat(position(), '. ', ., '&#xA;')"/>
Required type is xs:string; supplied value has type xs:integer"
1. Why doesn't the XSLT processor perform an implicit cast from
integer to string? This is quite natural, as any atomic type has a
string representation and can be converted to string.
This is a good example of what I meant during my talk at XML Europe
about life getting harder for XSLT users because of the strong typing
in XPath 2.0. XPath 2.0 allows implicit casting:

1. from xdt:untypedAtomic (the type of untyped nodes) to any atomic
type

2. from any atomic type to its base type (up the atomic type
hierarchy)

3. from xs:decimal (and its subtypes) to xs:float or xs:double and
from xs:float to xs:double

As you say, it is possible to cast values of most types into a string
(exceptions are xs:QName and xs:NOTATION), but in terms of the type
hierarchy used by XPath 2.0, it is not the case that every type is
derived from xs:string. (I guess you're aware of the recent XML-Dev
discussion on this topic.) So you have to perform the casting
explicitly.
Post by Dimitre Novatchev
2. My current solution is to use
string(position())
Is this the best/recommended solution?
Yes. For atomic values like the integer returned by position(), it
returns the same as xs:string(position()); the latter is just longer
and requires an extra namespace declaration.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Dimitre Novatchev
2003-05-11 14:59:26 UTC
Permalink
Thanks a lot Jeni and Andrew,
Post by Jeni Tennison
This is a good example of what I meant during my talk at XML Europe
about life getting harder for XSLT users because of the strong typing
1. from xdt:untypedAtomic (the type of untyped nodes) to any atomic
type
2. from any atomic type to its base type (up the atomic type
hierarchy)
3. from xs:decimal (and its subtypes) to xs:float or xs:double and
from xs:float to xs:double
As you say, it is possible to cast values of most types into a string
(exceptions are xs:QName and xs:NOTATION), but in terms of the type
hierarchy used by XPath 2.0, it is not the case that every type is
derived from xs:string. (I guess you're aware of the recent XML-Dev
discussion on this topic.) So you have to perform the casting
explicitly.
Do any examples exist when such implicit casting would be
dangerous/counter-intuitive? If not, then it would be very useful to allow
implicit casting to string. In C++ one can specify a constructor that takes
a single argument og another type, e.g.:

class complex
{
double re, im;

public:
complex (double r) : re(r), im(0) {}

};

Then the programmer simply writes:

complex a = 7;

instead of

complex a = complex(7);


In cases like the current one I think such "conversion constructors" should
be specified in the XPath data model. This makes writing and understanding a
program much more easier.
Post by Jeni Tennison
Post by Dimitre Novatchev
2. My current solution is to use
string(position())
Is this the best/recommended solution?
Yes. For atomic values like the integer returned by position(), it
returns the same as xs:string(position()); the latter is just longer
and requires an extra namespace declaration.
Thanks!


=====
Cheers,

Dimitre Novatchev.
http://fxsl.sourceforge.net/ -- the home of FXSL




XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Jeni Tennison
2003-05-11 21:09:00 UTC
Permalink
Hi Dimitre,
Post by Dimitre Novatchev
Do any examples exist when such implicit casting would be
dangerous/counter-intuitive? If not, then it would be very useful to
allow implicit casting to string.
I agree, but then I think that it would be useful to allow implicit
casting to a required type, whatever it is, if such a cast is
permitted. Those that support strong typing in XPath 2.0, on the other
hand, believe that it's useful to be told that you can't use an
integer where a string is expected.

There are lots of cases where there *is* implicit casting (of
xdt:untypedAtomic values) in XPath 2.0 and that casting is
counter-intuitive (to XPath 1.0 users). For example:

@height > @weight

casts both attributes to strings and compares them lexicographically,
rather than doing a numeric comparison as in XPath 1.0, while:

current-dateTime() + @delay

(where @delay is "PT30M", for example) will give you a type error
because the delay attribute is cast to an xs:double (even though you
can't actually add an xs:double to an xs:dateTime) and "PT30M" isn't a
valid double value.

Similarly:

24 idiv (@indent + 3)

will give you a type error because the indent attribute is cast to an
xs:double, which means the result of (@indent + 3) is an xs:double,
which isn't a valid type for an operand to idiv.

Which I guess goes to show that implicit casting coupled with
polymorphic operators will always give some weird results.
Post by Dimitre Novatchev
In cases like the current one I think such "conversion constructors"
should be specified in the XPath data model. This makes writing and
understanding a program much more easier.
The rules for casting between types are specified in the XPath/XQuery
Functions & Operators document (http://www.w3.org/TR/xpath-functions).
As I said above, personally I don't see why these rules can't be used
for implicit casting, but this seems to go against the strong typing
ethos of XPath 2.0.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Dimitre Novatchev
2003-05-12 05:13:26 UTC
Permalink
Hi Jeni,
Post by Jeni Tennison
Post by Dimitre Novatchev
Do any examples exist when such implicit casting would be
dangerous/counter-intuitive? If not, then it would be very useful to
allow implicit casting to string.
I agree, but then I think that it would be useful to allow implicit
casting to a required type, whatever it is, if such a cast is
permitted.
Absolutely -- this is logical, intuitive and will be a time saver.
Post by Jeni Tennison
Those that support strong typing in XPath 2.0, on the other
hand, believe that it's useful to be told that you can't use an
integer where a string is expected.
Yes, so an XSLT processor could issue a warning. Only in the "weird" cases this warning will
really be useful to help find the reason of the "weirdness".
Post by Jeni Tennison
There are lots of cases where there *is* implicit casting (of
xdt:untypedAtomic values) in XPath 2.0 and that casting is
@height > @weight
Sigh... nothing can be done here, since ">" has now been defined for strings. This is the case
when casting is possible to more than one type and nobody knows what is "correct" for the current
programmer. In this case explicit casting is necessary.

To formulate it more precisely, when there's no ambiguity, implicit casting to the type of an
argument should be performed. We agree that this is a job for the XSLT processor (no ambiguity and
perfect knowledge of type signatures) that will significantly help the programmer (prone to
forgetting and commiting errors).
Post by Jeni Tennison
because the delay attribute is cast to an xs:double (even though you
can't actually add an xs:double to an xs:dateTime) and "PT30M" isn't a
valid double value.
The same case again -- the implicit cast must be to the only known correct type for the operation.
Post by Jeni Tennison
will give you a type error because the indent attribute is cast to an
which isn't a valid type for an operand to idiv.
Again the same case as above. Someone would argue that the decision to what type to cast will
depend on the order of evaluation (,which in an FP language is not strictly defined). However,
human beings tend to write expressions in a predefined way (e.g. from left to write), so the same
should be used in the casting of types of operands -- of course, after the casting decisions are
made the expression can still be evaluated in any possible order.
Post by Jeni Tennison
Which I guess goes to show that implicit casting coupled with
polymorphic operators will always give some weird results.
Not in the cases where there's no ambiguity. And warnings will be helpful if a few weird cases
still remain.
Post by Jeni Tennison
Post by Dimitre Novatchev
In cases like the current one I think such "conversion constructors"
should be specified in the XPath data model. This makes writing and
understanding a program much more easier.
The rules for casting between types are specified in the XPath/XQuery
Functions & Operators document (http://www.w3.org/TR/xpath-functions).
As I said above, personally I don't see why these rules can't be used
for implicit casting,
Agreed. What can be done to have this in the spec?
Post by Jeni Tennison
but this seems to go against the strong typing
ethos of XPath 2.0.
And there can be warnings to that effect.




=====
Cheers,

Dimitre Novatchev.
http://fxsl.sourceforge.net/ -- the home of FXSL

__________________________________
Do you Yahoo!?
The New Yahoo! Search - Faster. Easier. Bingo.
http://search.yahoo.com

XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Michael Kay
2003-05-13 01:03:17 UTC
Permalink
Post by Dimitre Novatchev
Hi Mike and Jeni,
<xsl:value-of select="concat(position(), '. ', ., '&#xA;')"/>
Required type is xs:string; supplied value has type xs:integer"
1. Why doesn't the XSLT processor perform an implicit cast
from integer to string? This is quite natural, as any atomic
type has a string representation and can be converted to string.
I agree with you that it would be very natural for concat() to do
implicit conversion of its arguments to strings. It's interesting that
the "+" operator in Java is exceptional in this regard; it is the only
weakly typed operator in an otherwise strongly-typed language. I found
that in my library of test cases, supplying non-string arguments to
concat() was one of the most comment causes of type errors. (In
backwards compatibility mode, of course, it is still allowed.) I have
argued in the WG that concat() should be treated specially, but most of
my colleagues preferred to keep the rules consistent with other
functions. I suspect some were concerned that it might be the thin end
of the wedge towards a gradual reintroduction of weak typing into the
language generally.

There are probably two main justifications for not allowing function
arguments always to be cast to the required type. The first is error
checking - as the number of types increases, the risk increases of doing
a calculation that is different from the one the user actually intended.
The second is polymorphism. XPath 2.0 doesn't allow functions (as
distinct from operators) to be polymorphic, but some people would like
to keep the option open to allow it in future, and weak typing is not
really compatible with polymorphism.

Most languages end up being a bit pragmatic about this, and XPath is no
different. In the latest draft, we changed all the functions that accept
or return URIs to use the xs:string type instead of xs:anyURI, because
it was simply too much of a pain to keep casting strings to URIs and
back (though Java makes you do just that). For numerics, we introduced a
set of promotion rules that allow arithmetic to mix the different
numeric types.

There would be no technical difficulty in defining concat(), like
string(), to take item() rather than xs:string as its argument type.
It's just a question of persuading people that it deserves to be treated
as a special case.

The place for such comments, of course, is the public-qt-comments list.

Michael Kay


XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Dimitre Novatchev
2003-05-13 21:22:16 UTC
Permalink
Post by Michael Kay
There are probably two main justifications for not allowing function
arguments always to be cast to the required type. The first is error
checking - as the number of types increases, the risk increases of doing
a calculation that is different from the one the user actually intended.
The second is polymorphism. XPath 2.0 doesn't allow functions (as
distinct from operators) to be polymorphic, but some people would like
to keep the option open to allow it in future, and weak typing is not
really compatible with polymorphism.
I do not advocate weak typing. It is possible to avoid unnecessary explicit
casts/conversions with strong typing and still to support polymorphism to
the maximum extent possible.
Post by Michael Kay
class Show a where
show :: a -> String
showsPrec :: Int -> a -> ShowS
showList :: [a] -> ShowS
This defines the class of all types that have a "show" method, which will
present an instance of the datatype to a string.

The type "shows" is a synonym for any function from String to String
Post by Michael Kay
type ShowS = String -> String
-- Minimal complete definition: show or showsPrec
Post by Michael Kay
show x = showsPrec 0 x ""
showsPrec _ x s = show x ++ s
showList [] = showString "[]"
showList (x:xs) = showChar '[' . shows x . showl xs
where showl [] = showChar ']'
showl (x:xs) = showChar ',' . shows x . showl xs
As can be seen, the "showList" method can produce the string representation
of any list of things whose type belongs to the Show class. This is the
direct (and really precise) Haskell analog to the XSLT/XPath concat()
function.

As we see, in a well-designed strongly typed language, functions like
concat() may be defined in such a way so that no explicit conversion of the
arguments will be required.
Post by Michael Kay
class Eq a where
(==), (/=) :: a -> a -> Bool
-- Minimal complete definition: (==) or (/=)
Post by Michael Kay
x == y = not (x/=y)
x /= y = not (x==y)
Ord -- a class of all datatypes that belong to Eq and also have a total
Post by Michael Kay
class (Eq a) => Ord a where
compare :: a -> a -> Ordering
(<), (<=), (>=), (>) :: a -> a -> Bool
max, min :: a -> a -> a
-- Minimal complete definition: (<=) or compare

-- using compare can be more efficient for complex types
Post by Michael Kay
compare x y | x==y = EQ
| x<=y = LT
| otherwise = GT
x <= y = compare x y /= GT
x < y = compare x y == LT
x >= y = compare x y /= LT
x > y = compare x y == GT
max x y | x <= y = y
| otherwise = x
min x y | x <= y = x
| otherwise = y
Class Bounded

Class Num



etc.

This is a nice example how unnecessary casts/conversions can be avoided,
while still preserving and supporting polymorphism.

=====
Cheers,

Dimitre Novatchev.
http://fxsl.sourceforge.net/ -- the home of FXSL
Post by Michael Kay
Most languages end up being a bit pragmatic about this, and XPath is no
different. In the latest draft, we changed all the functions that accept
or return URIs to use the xs:string type instead of xs:anyURI, because
it was simply too much of a pain to keep casting strings to URIs and
back (though Java makes you do just that). For numerics, we introduced a
set of promotion rules that allow arithmetic to mix the different
numeric types.
There would be no technical difficulty in defining concat(), like
string(), to take item() rather than xs:string as its argument type.
It's just a question of persuading people that it deserves to be treated
as a special case.
The place for such comments, of course, is the public-qt-comments list.
Michael Kay
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Loading...