<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://www.w3.org/Bugs/Public/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.4"
          urlbase="https://www.w3.org/Bugs/Public/"
          
          maintainer="sysbot+bugzilla@w3.org"
>

    <bug>
          <bug_id>29723</bug_id>
          
          <creation_ts>2016-07-07 15:31:06 +0000</creation_ts>
          <short_desc>[FO31] map:merge</short_desc>
          <delta_ts>2016-12-16 19:55:33 +0000</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>1</classification_id>
          <classification>Unclassified</classification>
          <product>XPath / XQuery / XSLT</product>
          <component>Functions and Operators 3.1</component>
          <version>Candidate Recommendation</version>
          <rep_platform>PC</rep_platform>
          <op_sys>Windows NT</op_sys>
          <bug_status>CLOSED</bug_status>
          <resolution>FIXED</resolution>
          
          
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords></keywords>
          <priority>P2</priority>
          <bug_severity>normal</bug_severity>
          <target_milestone>---</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter name="Tim Mills">tim</reporter>
          <assigned_to name="Michael Kay">mike</assigned_to>
          <cc>abel.braaksma</cc>
          
          <qa_contact name="Mailing list for public feedback on specs from XSL and XML Query WGs">public-qt-comments</qa_contact>

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>126908</commentid>
    <comment_count>0</comment_count>
    <who name="Tim Mills">tim</who>
    <bug_when>2016-07-07 15:31:06 +0000</bug_when>
    <thetext>The &quot;use-last&quot; policy for map:merge means that the implementation has to process the entire input before it can determine the output.  This used to be the case for parse-json, but a change was made to parse-json so that it defaulted to &quot;use-first&quot;.

Should map:merge not have a similar option, and a similar default?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>126939</commentid>
    <comment_count>1</comment_count>
    <who name="Michael Kay">mike</who>
    <bug_when>2016-07-10 09:38:47 +0000</bug_when>
    <thetext>Note also: in map:merge, the sentence (in a Note)

&quot;This means that in edge cases, where (as a result of numeric promotion) the ·same key· relation is not transitive, different implementations may give different results.&quot;

is obsolete and should be deleted.

Otherwise, my preference is for the status quo. I don&apos;t think the rationale given is strong enough to justify a change.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>126989</commentid>
    <comment_count>2</comment_count>
    <who name="Michael Kay">mike</who>
    <bug_when>2016-07-19 17:22:58 +0000</bug_when>
    <thetext>ACTION A-650-02: Action on Mike Kay to write a proposal for adding options to map merge (use-first, use-last, reject, combine, don’t care).  

Proposal (in addition to deleting the redundant sentence mentioned above).

Add an optional second argument to map:merge, so there are two signatures:

map:merge($maps as map(*)*) as map(*)
map:merge($maps as map(*)*, $options as map(*)) as map(*)

&lt;quote&gt;
The effect of the arity-1 function is the same as the effect of the arity-2 function when an empty map is supplied as the value of $options.

The $options argument can be used to control the way in which duplicate keys are handled. The ·option parameter conventions· apply.

The entries that may appear in the $options map are as follows:

Key	Value	Meaning

duplicates	Determines the policy for handling duplicate keys, when two or maps in the value of $maps contain the *same key*. The required type is xs:string. The default value is &quot;use-first&quot;.

reject	An error is raised [err:FOJS0003] if duplicate keys are encountered.

use-first	If duplicate keys are present, all but the first of a set of duplicates are ignored, where the ordering is based on the order of maps in the $maps argument.

use-last	If duplicate keys are present, all but the last of a set of duplicates are ignored, where the ordering is based on the order of maps in the $maps argument.

combine         If duplicate keys are present, the result map includes an entry for the key whose associated value is the sequence-concatenation of all the values associated with the key, retaining order based on the order of maps in the $maps argument.

unspecified     If duplicate keys are present, the effect is implementation-defined; the implementation may choose one of the above strategies for handling duplicates, or may choose some other strategy.

Informally, the supplied maps are combined as follows:

There is one entry in the returned map for each distinct key present in the union of the input maps, where two keys are distinct if they are not the ·same key·.

For any key that appears in only one of the input maps, the associated value for that key in the result map is the same as the associated value in that input map.

For any key that appears in more than one of the input maps, the associated value for that key in the result map depends on the way in which duplicates are handled, as described above.

The definitive specification of map-merge#2 is as follows. The result of the function call map:merge($MAPS, $OPTIONS) is defined to be the result of the expression

let $FOJS0003 := QName(&quot;......&quot;, &quot;FOJS0003&quot;),

$duplicates-handler := map {
  &quot;use-first&quot;: function($a, $b) {$a},
  &quot;use-last&quot;: function($a, $b) {$b},
  &quot;combine&quot;: function($a, $b) {$a, $b},
  &quot;reject&quot;: function($a, $b) {error($FOJS0003)},
  &quot;unspecified&quot;: function($a, $b) {{#vendor:defined#}{}}
},

$combine-maps := function($A as map(*), $B as map(*), $deduplicator as function(*)) {
    fn:fold-left(map:keys($B), $A, function($z, $k){ 
        if (map:contains($z, $k))
        then map:put($z, $k, $deduplicator($z($k), $B($k)))
        else map:put($z, $k, $B($k))
    })
}
return fn:fold-left($MAPS, map{}, 
    $combine-maps(?, ?, $duplicates-handler(($OPTIONS?duplicates, &quot;use-first&quot;)[1]))
            

&lt;/quote&gt;

Change the example map:merge(($week, map{6:&quot;Sonnabend&quot;})) to illustrate the various options:

reject -&gt; error
use-first -&gt; 6:&quot;Samstag&quot;
use-last -&gt; 6:&quot;Sonnabend&quot;
combine -&gt; 6:(&quot;Samstag&quot;, &quot;Sonnabend&quot;)
unspecified -&gt; result is implementation-defined.

Change the example of map:merge that appears under fn:collation:key.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>126990</commentid>
    <comment_count>3</comment_count>
    <who name="Michael Kay">mike</who>
    <bug_when>2016-07-19 17:27:05 +0000</bug_when>
    <thetext>In addition, in XSLT §21.3, the specification of the xsl:map instruction can be changed to replace

let $keys := $maps!map:keys(.)
return if (count($keys) = count(distinct-values($keys)))
       then map:merge($maps)                        
       else error()

with the simpler formulation

map:merge($maps, map{&quot;duplicates&quot;:&quot;reject&quot;})</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>127003</commentid>
    <comment_count>4</comment_count>
    <who name="Abel Braaksma">abel.braaksma</who>
    <bug_when>2016-07-20 13:42:44 +0000</bug_when>
    <thetext>&gt; unspecified     If duplicate keys are present, the effect is 
&gt; implementation-defined; the implementation may choose one of the above 
&gt; strategies for handling duplicates, or may choose some other strategy.
I would like to suggest that &quot;unspecified&quot; may not act as &quot;combine&quot; or &quot;reject&quot;, because that results in a functional and too unpredictable difference. It should act as a &quot;use-first&quot;, &quot;use-last&quot; or &quot;use-either&quot;, in other words, the only unpredictability of &quot;unspecified&quot; is whether the LH-value or the RH-value of any given key is used.

If we wouldn&apos;t do this, a user cannot know whether he gets a combined sequence for a given key, or whether he should add a try/catch.

This then also resolves another use-case: if the user knows that duplicate keys exist, but with the same or exchangeable value, &quot;unspecified&quot; would become the optimal strategy, where the implementer can choose either value and can short-circuit evaluation, but will not error, or combine.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>127004</commentid>
    <comment_count>5</comment_count>
    <who name="Abel Braaksma">abel.braaksma</who>
    <bug_when>2016-07-20 13:47:36 +0000</bug_when>
    <thetext>To make that concrete, I&apos;d propose a text like this:

unspecified     If duplicate keys are present, the chosen value is implementation-defined; the implementation may choose the &quot;use-first&quot; or &quot;use-last&quot; strategy for handling duplicates, or may choose some other strategy. The implementation may not combine or raise an error on duplicates if this option is chosen.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>127005</commentid>
    <comment_count>6</comment_count>
    <who name="Abel Braaksma">abel.braaksma</who>
    <bug_when>2016-07-20 13:51:35 +0000</bug_when>
    <thetext>Sorry, I think this is better (ignore comment 5), and better complements the existing wording:

unspecified      If duplicate keys are present, all but one of a set of duplicates are ignored, where it is implementation-defined which item from the set is chosen.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>127059</commentid>
    <comment_count>7</comment_count>
    <who name="Michael Kay">mike</who>
    <bug_when>2016-07-26 20:12:01 +0000</bug_when>
    <thetext>The proposal in comment 2 was accepted as modified by comment 6, with the additional proviso that the effect of &quot;unspecified&quot; is implementation-dependent rather than implementation-defined.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>127060</commentid>
    <comment_count>8</comment_count>
    <who name="Michael Kay">mike</who>
    <bug_when>2016-07-26 20:28:13 +0000</bug_when>
    <thetext>Test cases have been updated.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>127061</commentid>
    <comment_count>9</comment_count>
    <who name="Michael Kay">mike</who>
    <bug_when>2016-07-26 22:07:41 +0000</bug_when>
    <thetext>The F+O 3.1 and XSLT 3.0 specifications have been updated.</thetext>
  </long_desc>
      
      

    </bug>

</bugzilla>