Some thoughts on function bodies and <sequence>

All,

I dug up some emails and found Mike's reply in November 2009 on the topic:

"I would recommend, if you want to keep things simple, only allowing
xforms:sequence [as opposed to also supporting xforms:value-of]. Or
naming it xforms:return - that's what it was in XSLT until we
generalized it to allow sequence constructors, and in many ways I
regret changing it."

That sounds like a good suggestion to me, assuming we are going to
support an element to specify the result.

Now I am wondering if we can do away with nested elements altogether.
I would like to see things like this, based on the examples in [1]:

Example 1:

<function signature="my:sum($p as xs:integer, $q as xs:integer) as xs:integer">
    $p + $q
</function>

Or, using @value:

<function signature="my:sum($p as xs:integer, $q as xs:integer) as
xs:integer" value="$p + $q"/>

Example 2 (XPath 3):

<function signature="dollar-round($num as xs:decimal) as xs:string">
    let $num100str := string(round($num * 100)),
        $trunc := substring-before($num100str, '.'),
        $intpart = substring($trunc, 0, string-length($trunc)-2),
        $fracpart = substring($trunc, string-length($intpart), 2)

    return concat($intpart, '.', $fracpart)
</function>

(I am sure you can write that function better in XPath 2 or XPath 3 BTW!)

@value can also be used here, but it's a bit more clumsy visually.

Example 3:

<function signature="my:sumproduct($p as node()*, $q as node()*) as xs:double">
   sum(for $i in 1 to count($p) return $p[$i] * $q[$i])
</function>

or:

<function signature="my:sumproduct($p as node()*, $q as node()*) as xs:double"
    value="sum(for $i in 1 to count($p) return $p[$i] * $q[$i])"/>

This would work well for JavaScript too:

Example 1 (JavaScript):

<function signature="my:sum($p as xs:integer, $q as xs:integer) as
xs:integer" type="javascript>
    return p + q
</function>

<function signature="dollar-round($num as xs:decimal) as xs:string"
type="javascript>
    var num100str = ...
    var trunc = ...
    var intpart = ...
    var fracpart = ...

    return intpart + "." + fracpart
</function>

etc.

Now unfortunately in XPath 2 we can't use `let`, but maybe we can
still get away with the <sequence> or <return> element:

<function signature="dollar-round($num as xs:decimal) as xs:string">
    <var name="num100str" value="string(round($num * 100))"/>
    <var name="trunc" value="substring-before($num100str, '.')"/>
    <var name="intpart" value="substring($trunc, 0, string-length($trunc)-2)"/>
    <var name="fracpart" value="substring($trunc, string-length($intpart), 2)"/>

    concat($intpart, '.', $fracpart)
</function>

This allows functions that don't need variables in XPath 2 to keep the
return value as an expression within the body of the <function>
element, while still providing help to the poort XPath 2 or XPath 1
users that want to use variables.

Alternatively, we could completely get rid of the nested <var>
element. This would mostly impact XPath 1 and XPath 2 implementations,
with the idea that implementations would tend to migrate to XPath 3 as
soon as possible anyway.

So to summarize some ideas above:

1. We should consider using <return> instead of <sequence> if we do
decide to use an element for return values.
2. However, we should consider *not* using an element for return values at all.
3. We should consider allowing function bodies simply as the content
of <function>.
4. We should also support a shorthand with the @value attribute.
5. We might consider dropping support for nested <var> within
<function> (not so sure about this one).

Food for thoughts.

-Erik

[1] http://www.w3.org/MarkUp/Forms/wiki/Custom_XPath_functions

Received on Wednesday, 14 March 2012 17:02:14 UTC