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 27059 - [xp3.1] Function coercion, maps and arrays
Summary: [xp3.1] Function coercion, maps and arrays
Status: RESOLVED FIXED
Alias: None
Product: XPath / XQuery / XSLT
Classification: Unclassified
Component: XPath 3.1 (show other bugs)
Version: Working drafts
Hardware: PC All
: P2 minor
Target Milestone: ---
Assignee: Jonathan Robie
QA Contact: Mailing list for public feedback on specs from XSL and XML Query WGs
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-10-15 14:57 UTC by Michael Kay
Modified: 2015-10-06 15:30 UTC (History)
1 user (show)

See Also:


Attachments

Description Michael Kay 2014-10-15 14:57:31 UTC
Although the spec is probably technically correct, it would be worth some explanation of how function coercion interacts with maps and arrays.

Firstly, if the expected type is a map or array type, then function coercion does not apply. That's because the expected type is not [written as a] TypedFunctionTest (bullet 3 of 3.1.5.2). Note that the bullets here are rather varied in style, for example:

"If the expected type calls for a single item or optional single item"
"If the expected type is xs:string or xs:string?"
"If the expected type is a sequence of a generalized atomic type"

It would be better if they were all phrased in terms of how the type is expressed syntactically.

Secondly, if the expected type is (expressed as) a TypedFunctionTest, and the actual supplied value is a map or array, then function coercion does apply. For example, fn:sort expects a function item of type function(item()) as xs:anyAtomicType*, and it is acceptable to supply a map as the value of this argument. If a map $M is passed, the rules of function coercion say that this is equivalent to passing the function

function($key as item()) as xs:anyAtomicType* {
  $M($key)
}

which in general (unless there is an atomization failure) will work; the sort key for any value not present in the map is an empty sequence.

It's certainly worth a note or an example to explain this.

Thirdly, if the expected type is written as function(*), then it is legal to supply a map or array as the value of the argument, but no coercion takes place.
Comment 1 Jonathan Robie 2014-10-28 19:49:22 UTC
I need to rewrite this as a result of 21893. I will see what can be made clearer when I do that rewrite.
Comment 2 Michael Kay 2015-07-06 08:38:39 UTC
It appears that no changes have been made to the spec in response to this issue.
Comment 3 John Snelson 2015-07-16 19:54:43 UTC
To be resolved editorially.
Comment 4 John Snelson 2015-07-16 20:32:29 UTC
An example of function coercion against a map item to include in the spec:

let $m := map {
  "Monday" : true(),
  "Wednesday" : true(),
  "Friday" : true(),
  "Saturday" : false(),
  "Sunday" : false()
}
let $days := ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
return fn:filter($days,$m)


The map $m has a function signature of function(xs:anyAtomicType) as item()*. When the fn:filter() function is called, the following occurs to the fun\
ction:

1. The map $m is treated as function ($f) equivalent to map:get($m,?).
2. The function conversion rules result in applying function coercion to $f, wrapping $f in a new function ($p) with the signature function(item()) as\
 xs:boolean.
3. $p is matched against the SequenceType of function(item()) as xs:boolean, and succeeds.
4. When $p is invoked by fn:filter(), function conversion and SequenceType matching rules are applied to the argument, resulting in an item() value ($\
a) or a type error.
5. $f is invoked with $a, which returns an xs:boolean or the empty sequence.
6. $p applies function conversion rules and SequenceType matching to the result sequence from $f. When the result is an xs:boolean the SequenceType ma\
tching succeeds. When it is an empty sequence (such as when $m does not contain a key for "Tuesday"), SequenceType matching results in a type error.
Comment 5 Jonathan Robie 2015-07-16 20:42:51 UTC
(In reply to John Snelson from comment #4)
> An example of function coercion against a map item to include in the spec:
> 
> let $m := map {
>   "Monday" : true(),
>   "Wednesday" : true(),
>   "Friday" : true(),
>   "Saturday" : false(),
>   "Sunday" : false()
> }
> let $days := ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
> "Saturday", "Sunday")
> return fn:filter($days,$m)

This returns:

[XPTY0004] xs:boolean expected, empty sequence found.

I would also like an example that filters, so I plan to provide both the example above and this one:

let $m := map {
"Monday" : true(),
"Tuesday" : false(),
"Wednesday" : true(),
"Thursday" : false(),
"Friday" : true(),
"Saturday" : false(),
"Sunday" : false()
}
let $days := ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
return fn:filter($days,$m)

=> 

Monday
Wednesday
Friday
Comment 6 Jonathan Robie 2015-10-06 15:30:16 UTC
I started adding this to the spec, but had some concerns with parts of this as I went.

(In reply to Michael Kay from comment #0)
> Although the spec is probably technically correct, it would be worth some
> explanation of how function coercion interacts with maps and arrays.
> 
> Firstly, if the expected type is a map or array type, then function coercion
> does not apply. That's because the expected type is not [written as a]
> TypedFunctionTest (bullet 3 of 3.1.5.2). 

I assume that does not need to be stated explicitly, since lots of other things aren't TypedFunctionTest.

> Note that the bullets here are
> rather varied in style, for example:
> 
> "If the expected type calls for a single item or optional single item"
> "If the expected type is xs:string or xs:string?"
> "If the expected type is a sequence of a generalized atomic type"
> 
> It would be better if they were all phrased in terms of how the type is
> expressed syntactically.

Do you mean by adding a phrase like "written as a"? Or were you asking for something else?

> Secondly, if the expected type is (expressed as) a TypedFunctionTest, and
> the actual supplied value is a map or array, then function coercion does
> apply. For example, fn:sort expects a function item of type function(item())
> as xs:anyAtomicType*, and it is acceptable to supply a map as the value of
> this argument. 

I think you're simply pointing out that arrays and maps are functions?  If so, it may be worth mentioning in a NOTE, e.g.

     
* If the expected type is a TypedFunctionTest (possibly with an occurrence indicator *, +, or ?), function coercion is applied to each function in the given value.
NOTE: Maps and arrays are functions, so function coercion applies to them as well.


> If a map $M is passed, the rules of function coercion say
> that this is equivalent to passing the function
> 
> function($key as item()) as xs:anyAtomicType* {
>   $M($key)
> }
> 
> which in general (unless there is an atomization failure) will work; the
> sort key for any value not present in the map is an empty sequence.
> 
> It's certainly worth a note or an example to explain this.

I would probably use the NOTE I suggested above, and add an example in the section on function coercion.

> Thirdly, if the expected type is written as function(*), then it is legal to
> supply a map or array as the value of the argument, but no coercion takes
> place.

I think this is covered by the above NOTE, and should also be covered in the example.