qt4cg / qtspecs

QT4 specifications
https://qt4cg.org/
Other
28 stars 15 forks source link

Add xsl:value-of/@as attribute #1272

Closed michaelhkay closed 1 month ago

michaelhkay commented 2 months ago

It has been suggested that we should add an @as attribute to xsl:value-of.

The intent is to use this when returning a function result:

<xsl:function name="f:incr">
  <xsl:param name="x" as="xs:integer"/>
  <xsl:value-of select="$x+1" as="xs:integer"/>
</xsl:function>

In the absense of the @as attribute, the instruction constructs a text node as now. If @as is added, the effect of the instruction is to evaluate the select expression and coerce the result to the specified type.

There are a number of questions of detail. What do we do about the @separator and @disable-output-escaping attributes? Do we allow as="text()" so that there is an explicit way of getting the default behavior?

More generally, will this actually make users' lives easier? It might read better than xsl:sequence in this situation, but it isn't any more discoverable. Users who write code by copy-and-paste will still write xsl:value-of without realising the significance of the @as attribute.

MarkNicholls commented 2 months ago

I must have missed the point.

why wouldnt I go

<xsl:function name="f:incr" as="xs:integer">
  <xsl:param name="x" as="xs:integer"/>
  <xsl:sequence select="$x+1"/>
</xsl:function>

?

ndw commented 2 months ago

I believe the concern is just one of usability. For many, xsl:value-of sounds like the way to compute a single value and it works in a lot of cases, even when the way it works involves creating a text node and coercing it back to some other atomic value. Using xsl:sequence is absolutely correct, but seems a little odd for a single value, especially if you're new to XPath.

michaelhkay commented 1 month ago

I'm not convinced that the proposal actually helps matters.

Instead I propose that we introduce an xsl:item instruction, and give both xsl:item and xsl:sequence an @as attribute

Arithmeticus commented 1 month ago

I don't fully understand the problems in adding @as to xsl:value-of. Put another way, if we can do this...

<xsl:variable name="item" as="xs:integer">
    <xsl:value-of select="1"/>
</xsl:variable>

...then why can't we do this...

<xsl:value-of as="xs:integer" select="1"/>

...and define the behavio(u)r of the latter in terms of the former?

michaelhkay commented 1 month ago

I don't fully understand the problems in adding @as to xsl:value-of.

The semantics of <xsl:value-of select="1"/> are to take the sequence resulting from the select expression and convert it to a text node using the (complicated) rules for constructing simple content. In this particular case the result is a text node with the string value "1", but other cases like <xsl:value-of select="1 to 10" separator=","/> the effects are more subtle.

Now you could define the semantics of <xsl:value-of select="1" as="xs:integer"/> in two different ways. You could do what you have suggested and say that it constructs the text node with string value "1" and then applies the coercion rules which atomize this and turn it back into an integer. Or you could say that the presence of the as clause prevents the usual behaviour of constructing a text node, and instead converts the select value directly to xs:integer using the coercion rules. Neither of these approaches give very satisfactory results, in fact both result in rather complex interactions between the rules for interpreting different attributes (select, as, separator, disable-output-escaping) on the instruction.

For example, would you expect <xsl:value-of select="1 to 5" as="xs:integer*"/> to work, and if so how? Would you still expect it to work if separator="," were added?

Clearly

<xsl:variable name="n" as="xs:integer*">
   <xsl:value-of select="1 to 5"/>
</xsl:variable>

currently fails: the text node with string value "1 2 3 4 5" cannot be coerced to a sequence of integers.

Arithmeticus commented 1 month ago

My first inclination is to make @as mutually exclusive to @separator. I assume that when someone adds @as to xsl:value-of it's because they are unhappy encountering (wittingly or unwittingly) the results of a text node, and they want the value to take a different form.

By the same logic, I would argue that the presence of @as in xsl:value-of -- an explicit request to depart from the default behavior -- should result in treating the element the same as xsl:sequence with @as.

The XSLT element xsl:value-of is one of the most poorly named in the suite. Dare I say it, the name is misleading. XPath defines (2.1.1) a "value" as a sequence of zero or more items (atomic values, nodes, function items). It takes some of us years before we figure out that xsl:value-of does not generate just any XPath value.

By introducing @as to xsl:value-of I think we have an opportunity to improve our tacit contract with users, that the specifications use terms such as "value" consistently.

MarkNicholls commented 1 month ago

I would find an already confusing xsl:value-of even more confusing and misleading should it have either of the semantics described above, in my head its deprecated and there for convenience in back compatibility, adding behaviour on top I find confusing.

michaelhkay commented 1 month ago

I think the behaviour of the desired instruction is sufficiently different from the existing xsl:value-of that it should be a different instruction; having two instructions that are completely different and share nothing except their name seems a bad idea.

MarkNicholls commented 1 month ago

ok, that seems sensible, but I'm struggling to see a good motivation for a new instruction? (I have no massive problem with an "as" on an xsl:sequence, you could argue its unnecessary, but I have actually tried to do it to see what happens).

ndw commented 1 month ago

The motivation for a new instruction, as I understand it, isn't really technical. It's about usability, especially for new or inexperienced users. If you want to return $a + $b, <xsl:value-of select="$a + $b"/> feels right: give me the value of a plus b. But often it isn't. Using xsl:sequence instead is right, but often feels unnatural: but it's not a sequence, it's just a single value! (That all single values are sequences of length one is a technical detail not immediately grasped by new users in my experience.)

I don't have a strong opinion about whether or not adding xsl:item to address this usability trap is worth the cost or not. As we saw in the discussions yesterday, there's some subtlty especially around whether xsl:item should be allowed to return the empty sequence.

From 10,000 feet, it seems tempting to add select to xsl:text and deprecate xsl:value-of. But there are countless tens of thousands of stylesheets out there with xsl:value-of in them; it's not going away in our lifetimes. So what's the real value even in doing that?

I guess one's answer depends partly on speculation about how the new features will be used and whether they will be viewed as aids or added complexity by users.

MarkNicholls commented 1 month ago

I've been worn down over the backwards compatibility thing, I accept its the reality.

An new way to do xsl:sequence to me is confusing and misleading added complexity, I think its better to encourage the users to understand the actual model, not present them things that they may find more intuitive, but are actually mirages, they will just fall down later harder when they're running faster.

michaelhkay commented 1 month ago

All very sound comments. We need to recognize the fact that however many people fall into an elephant trap in the language design, it's almost impossible to stop future users falling into the same trap by adding new features to the language. The only way to do it is to break compatibility by removing the elephant trap, and the pain of doing that for the existing user community usually exceeds the benefit.

johnlumley commented 1 month ago

Thinking a bit more about the idea mooted on permitting @as anywhere there is @select, I suggest that this only makes sense when it the result of the containing instruction is effectively the (XDMValue) @select XPath expression, possibly type coerced. For example this is the case for xsl:sequence and xsl:variable, but not the case for xsl:number nor indeed xsl:value-of or even in the extreme xsl:for-each

michaelhkay commented 1 month ago

I proposed that we close this with no action. We know there's a usability problem, but this isn't the solution.

ndw commented 1 month ago

The CG agreed to close this issue without further action at meeting 086.