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 24726 - map:new() and map:merge()
Summary: map:new() and map:merge()
Status: CLOSED FIXED
Alias: None
Product: XPath / XQuery / XSLT
Classification: Unclassified
Component: XSLT 3.0 (show other bugs)
Version: Working drafts
Hardware: PC Linux
: P2 normal
Target Milestone: ---
Assignee: Michael Kay
QA Contact: Mailing list for public feedback on specs from XSL and XML Query WGs
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 24999
  Show dependency treegraph
 
Reported: 2014-02-19 08:23 UTC by Jonathan Robie
Modified: 2014-05-15 23:35 UTC (History)
1 user (show)

See Also:


Attachments

Description Jonathan Robie 2014-02-19 08:23:47 UTC
XPath can now create empty arrays or create arrays from literals, two of the uses of map:new().  

The third use is to merge arrays - for this purpose it would be helpful to have a more meaningful name.  Consider the following two expressions, which differ only by the name of the function:

$map => map:new( { "counter" : $map($key) + 1 } )

$map => map:merge( { "counter" : $map($key) + 1 } )

To my eyes, the meaning is much more obvious with  the name map:merge().

I suggest:

1. Either keep the zero-arity and 1-arity map:new() as is or drop them in favor of the new constructors.

2. Create a new function called map:merge() with the same semantics as the current map:new() with arity greater than 1
Comment 1 Michael Kay 2014-02-19 13:42:15 UTC
The most recent decision of the joint WGs is that arrays are no longer a specialisation of maps. Presumably, therefore, this bug report is obsolete? At any rate, many of the justifications it uses no longer apply.
Comment 2 Jonathan Robie 2014-02-19 17:23:17 UTC
Hi Mike,

I must be exhausted, I don't know why I said 'arrays' when I meant 'maps'. Here is the corrected text.

----------------------

XPath can now create empty maps or create maps from literals, two of the uses of map:new().  

The third use is to merge maps - for this purpose it would be helpful to have a more meaningful name.  Consider the following two expressions, which differ only by the name of the function:

$map => map:new( { "counter" : $map($key) + 1 } )

$map => map:merge( { "counter" : $map($key) + 1 } )

To my eyes, the meaning is much more obvious with  the name map:merge().

I suggest:

1. Either keep the zero-arity and 1-arity map:new() as is or drop them in favor of the new constructors.

2. Create a new function called map:merge() with the same semantics as the current map:new() with arity greater than 1
Comment 3 Michael Kay 2014-03-11 17:04:28 UTC
I think it might be a good idea to review where we stand on namespaces for these functions before we review the local names.
Comment 4 Michael Kay 2014-03-20 17:12:09 UTC
The XSL WG telcon looked at this today briefly; we didn't feel ready to make a decision but there was some sympathy to the idea of keeping the map:new#0 function to create an empty map, and renaming map:new#1 as map:merge#1.

Given that we can also create a new map using the XPath 3.1 syntax map{}, the only real case for keeping map:new#0 is the transitional benefit that it provides a way of creating a map using functions alone, without relying on new syntax. But if the only purpose is transitional, then map:merge(()) (merging an empty set of maps to create an empty map) might be good enough for the requirement.
Comment 5 Michael Kay 2014-04-24 18:57:46 UTC
The WG looked at this today and agreed that it would be a good idea to try and find function names that more closely matched the tasks being performed, however elegant it might appear to have one multi-purpose function. The editor was asked to produce a proposal.

I'm inclined to go with the following:

(1) To create an empty map, use either map{} or map:merge(()).

(2) map:merge() acts lile the current map:new() - it takes a sequence of maps and merges them into a single map, resolving duplicate keys.

(3) To add an entry to a map (creating a new map), use map:put($map, $key, $value). The new entry replaces any existing entry with the same key. This function works well with the new function chaining operator: map{} => map:put("a", 1) => map:put("b", 2) (though of course simple cases like this can be done equally well with a map expression).

(4) map:entry() which creates a singleton map, can now be dropped. Anyone who really wants this function can either use map expressions, or implement it as 

let $map:entry := map:put(map{}, ?, ?)

So we end up with two functions map:merge() replacing map:new(), and map:put() replacing map:entry().
Comment 6 Abel Braaksma 2014-04-30 14:32:32 UTC
I agree to renaming map:merge. Also, allowing map{} makes sense, but it doesn't require a change, it is already allowed:

MapExpr ::= "map{" (KeyExpr ":" ValueExpr ("," KeyExpr ":" ValueExpr )*)? "}"

I would prefer to keep map:entry (or perhaps map:item) as the equivalent counterpart of xsl:map-entry (or xsl:map-item).

Note also that we used to have map:put, but don't have it anymore.

Furthermore, it strikes me as odd that map:put would _not_ throw an error if the item already existed. I would like to argue, in line with existing maps/dictionaries/hashsets in other programming languages, that adding an item that already exists is not allowed. We could consider both a map:put and map:set, where the latter overrides an existing entry, or adds it if it doesn't exist, and the former (map:put) raises an error if an item exists. Instead of map:put, perhaps map:add is better.

To summarize, I would like:
1) map:add (error if exists)
2) map:put/set (no error if exists, overwrites)
3) map:merge (as per MK's proposal)
4) map{} (as per MK's proposal)
5) map:entry (retain it)
6) remove map:new
Comment 7 Michael Kay 2014-05-13 13:08:04 UTC
The XSL WG looked at this on 8 May 2014. We propose, subject to the XQuery WG concurring, the following:

1. map:new#0 is dropped. An empty map can be constructed using map{}.

2. map:new#1 is renamed map:merge, with no change in behaviour.

3. A new function map:put($map, $key, $value) is defined. The semantics are equivalent to map:merge(($map, map{$key, $value}))
Comment 8 Michael Kay 2014-05-13 13:12:10 UTC
Item 3 in the previous comment should read:

3. A new function map:put($map, $key, $value) is defined. The semantics are equivalent to map:merge(($map, map{$key : $value}))
Comment 9 Jonathan Robie 2014-05-13 13:15:45 UTC
Looks good to me.
Comment 10 Michael Kay 2014-05-13 15:26:16 UTC
The proposal has been accepted by both XSL WG and XQuery WG and will be implemented in both XSLT 3.0 and F+O 3.1.