- From: Michael Kay <mike@saxonica.com>
- Date: Wed, 29 Jan 2025 10:55:54 +0000
- To: Christian Grün <cg@basex.org>
- Cc: "public-xslt-40@w3.org" <public-xslt-40@w3.org>
- Message-Id: <BF6795BE-3341-4470-82D1-FC5AC7A81854@saxonica.com>
> > > > Unfortunately this cannot be implemented using map:put as a primitive, because `map:put($map, $key, $value)` is currently defined to return a map in which the new `$key` replaces the old. > > My feeling is that the current definitions are a bit ambiguous or vague. XQFO 4.0 says for map:put: > > > The entry order of the entries in the returned map is as follows: if $map contains an entry whose key is $key, then the new value replaces the old value and the position of the entry is not changed; otherwise, the new entry is added after all existing entries. > > The last sentence implies that only the value is replaced. But the 3.1 spec is unambiguous that map:put replaces both the key and the value (specifically, map:put removes the old entry before adding a new entry). In addition, I think that is the normal action of put operations in the underlying libraries that implementations are likely to be using. It's possible that this was my rationale for leaving it implementation-dependent whether the old key or the new key is used; being over-prescriptive here could be excessiely constraining on implementations built on standard libraries. Mike > > XPDM says: > > > The key/value pairs in the returned map are as follows: > > • One key/value pair for every key/value pair present in $map whose key is not equal to $key; plus > > • One key/value pair whose key is $key and whose associated value is $value. > > The entry order in the returned map reflects the entry order in the supplied $map. If the key of the new entry was present in $map then the new entry replaces that entry retaining its current position; otherwise, the new entry is added after all existing entries. > > It implies that there will be a new entry (consisting of the supplied key and value) which will replace the old one. Maybe we can refine it: "If the key of the new entry was present in $map" implies that the key is exactly the same key, but we actually have 3 cases: > > 1. Keys are exactly the same (e.g., integers 1 and 1) > 2. Keys are regarded as equal, but are different (e.g., integer 1 and double 1e0) > 3. Keys are different (e.g., integers 1 and 2) > > I believe that 2. can be restricted to cases for which fn:atomic-equal returns true, but where the type of the compared keys differs. In https://github.com/qt4cg/qtspecs/issues/1725#issuecomment-2609624271, my proposal was to treat 2. and 3. identically: > > > Another edge case that may need to be refined in the spec is the replacement of different keys that are deemed equal (1 vs 1.0) with map:put: > > { 1: 'integer', 2e0: 'double' } => map:put(1.0, 'decimal') > > As the stored key is changed by this update, I think we should treat it not as an in-place update, but as a delete-and-insert operation. > > One advantage of this would be that the resulting order would unveil what has been going on. > > What do you think? > > > I considered using map:replace() instead of map:put(). The prose of map:replace suggests that the old key is retained, but the "formal equivalent" is defined using map:put(), which uses the new key. > > There is an open issue that may result in dropping map:replace. Maybe we could decide rather earlier than later whether we want to keep the function: https://github.com/qt4cg/qtspecs/issues/583. > > Thanks, > Christian
Received on Wednesday, 29 January 2025 10:56:13 UTC