<div dir="ltr">+1 I've been wishing the protocol had something like this.<div><br></div><div>It would be nice if a protocol extension had default implementations similar to these:</div><div><br></div><div><div style="font-size:13px"><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:rgb(187,44,162)">init</span><span style="color:rgb(0,0,0)"><S: </span>SequenceType<span style="color:rgb(0,0,0)"> </span><span style="color:rgb(187,44,162)">where</span><span style="color:rgb(0,0,0)"> </span>S<span style="color:rgb(0,0,0)">.</span>Generator<span style="color:rgb(0,0,0)">.</span>Element<span style="color:rgb(0,0,0)"> == </span>Generator<span style="color:rgb(0,0,0)">.</span>Element<span style="color:rgb(0,0,0)">>(</span><span style="color:rgb(187,44,162)">_</span><span style="color:rgb(0,0,0)"> sequence: </span>S<span style="color:rgb(0,0,0)">)</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:rgb(0,0,0)">{</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(187,44,162)">self</span><span style="color:rgb(0,0,0)">.init</span><span style="color:rgb(0,0,0)">(minimumCapacity: sequence.</span><span style="color:rgb(34,34,34)">underestimateCount()</span><span style="color:rgb(0,0,0)">)</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(187,44,162)">self</span><span style="color:rgb(0,0,0)">.</span><span style="color:rgb(0,0,0)">mergeContentsOf(sequence)</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:rgb(0,0,0)">}</span></div></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:rgb(0,0,0)"><br></span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span class="im" style="color:rgb(112,61,170)"><div style="margin:0px;line-height:normal"><span style="color:rgb(187,44,162)">init</span><S: SequenceType <span style="color:rgb(187,44,162)">where</span> S.Generator.Element == Generator.Element></div></span><div style="margin:0px;line-height:normal"><span style="color:rgb(112,61,170)"> (<span style="color:rgb(187,44,162)">_</span> sequence: S, <span style="color:rgb(187,44,162)">@noescape</span> combine: (Value, Value) <span style="color:rgb(187,44,162)">throws</span> -> Value</span><font color="#000000"> = { (_,x) in x }</font><font color="#703daa">) </font><span style="color:rgb(187,44,162)">rethrows</span></div><div style="margin:0px;line-height:normal"><span style="color:rgb(0,0,0)">{</span></div><div style="color:rgb(112,61,170);margin:0px;line-height:normal"><div style="margin:0px;line-height:normal"><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(187,44,162)">self</span><span style="color:rgb(0,0,0)">.init(minimumCapacity: sequence.</span><span style="color:rgb(34,34,34)">underestimateCount()</span><span style="color:rgb(0,0,0)">)</span></div><div style="margin:0px;line-height:normal"><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(187,44,162)">try</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(187,44,162)">self</span><span style="color:rgb(0,0,0)">.</span><span style="color:rgb(0,0,0)">mergeContentsOf(sequence, combine: </span><span style="color:rgb(0,0,0)">combine</span><span style="color:rgb(0,0,0)">)</span></div></div><div style="margin:0px;line-height:normal"><font color="#000000">}</font></div></div><div style="font-size:13px"><br></div><div style="font-size:13px"><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:rgb(187,44,162)">mutating</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(187,44,162)">func</span><span style="color:rgb(0,0,0)"> mergeContentsOf<S: </span>SequenceType<span style="color:rgb(0,0,0)"> </span><span style="color:rgb(187,44,162)">where</span><span style="color:rgb(0,0,0)"> </span>S<span style="color:rgb(0,0,0)">.</span>Generator<span style="color:rgb(0,0,0)">.</span>Element<span style="color:rgb(0,0,0)"> == </span>Generator<span style="color:rgb(0,0,0)">.</span>Element<span style="color:rgb(0,0,0)">></span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:rgb(0,0,0)"> (</span><span style="color:rgb(187,44,162)">_</span><span style="color:rgb(0,0,0)"> sequence: </span>S<span style="color:rgb(0,0,0)">)</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:rgb(0,0,0)">{</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(187,44,162)">for</span><span style="color:rgb(34,34,34)"> </span><span style="color:rgb(34,34,34)">(key, value)</span><span style="color:rgb(34,34,34)"> </span><span style="color:rgb(187,44,162)">in</span><span style="color:rgb(34,34,34)"> sequence </span><span style="color:rgb(34,34,34)">{</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:rgb(34,34,34)"> </span><span style="color:rgb(187,44,162)">self</span><span style="color:rgb(34,34,34)">[key] = value</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:rgb(34,34,34)"> }</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:rgb(0,0,0)">}</span></div></div><div style="font-size:13px"><span style="color:rgb(0,0,0)"><br></span></div><div style="font-size:13px"><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:rgb(187,44,162)">mutating</span> <span style="color:rgb(187,44,162)">func</span> mergeContentsOf<S: <span style="color:rgb(112,61,170)">SequenceType</span> <span style="color:rgb(187,44,162)">where</span> S.Generator.Element == <span style="color:rgb(112,61,170)">Generator</span>.Element></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"> (<span style="color:rgb(187,44,162)">_</span> sequence: S, <span style="color:rgb(187,44,162)">@noescape</span> combine: (Value, Value) <span style="color:rgb(187,44,162)">throws</span> -> Value<span style="color:rgb(0,0,0)"> </span><span style="color:rgb(0,0,0)">= { (_,x) in x }</span>) <span style="color:rgb(187,44,162)">rethrows</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:rgb(0,0,0)">{</span><br></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><div style="margin:0px;line-height:normal"><span style="color:rgb(187,44,162)"> for</span> (key, value) <span style="color:rgb(187,44,162)">in</span> sequence {</div><div style="margin:0px;line-height:normal"> <span style="color:rgb(187,44,162)">if</span> <span style="color:rgb(187,44,162)">let</span> oldValue = <span style="color:rgb(187,44,162)">self</span>[key] {</div><div style="margin:0px;line-height:normal"> <span style="color:rgb(187,44,162)">self</span>[key] = <span style="color:rgb(187,44,162)">try</span> combine(oldValue, value)</div><div style="margin:0px;line-height:normal"> }</div><div style="margin:0px;line-height:normal"><span style="color:rgb(187,44,162)"> else</span> {</div><div style="margin:0px;line-height:normal"> <span style="color:rgb(187,44,162)">self</span>[key] = value</div><div style="margin:0px;line-height:normal"> }</div><div style="margin:0px;line-height:normal"><span style="color:rgb(187,44,162)"> </span><span style="color:rgb(187,44,162)"> </span>}</div></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:rgb(0,0,0)">}</span><br></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><br></div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Jan 18, 2016 at 5:04 PM, Thorsten Seitz via swift-evolution <span dir="ltr"><<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><div></div><div>Alternatively the update method could take a combine function.</div><div>But I like the idea with using the dictionary index as opposed to the key.</div><div><br></div><div>-Thorsten</div><div><div class="h5"><div><br>Am 16.01.2016 um 11:28 schrieb Nicola Salmoria via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>>:<br><br></div><blockquote type="cite"><div><div dir="ltr"><div><div><div>+1 for the mutating methods. That's a pretty common use case and would nicely complement the Dictionary features.<br><br></div>As for the implementation details, I think all the examples we made are inefficient, requiring two dictionary lookups to combine a value. In e.g. C++ you can do something like this<br><br>auto it = m.find(x);<br>if (it != end(m)) {<br> it->second = value;<br>}<br><br></div><div>In Swift we have<br><br>func indexForKey(key: Key) -> DictionaryIndex<Key, Value>?<br></div><br>but then there are only<br><br>subscript(position: DictionaryIndex<Key, Value>) -> (Key, Value) { get }<br>mutating func removeAtIndex(index: DictionaryIndex<Key, Value>) -> (Key, Value)<br><br>It would probably be appropriate to have a new method<br><br>mutating func updateValue(value: Value, atIndex: DictionaryIndex<Key, Value>) -> Value<br><br></div><div>which would allow to efficiently combine the values with a single lookup.<br></div><div><br></div>Nicola<br><br></div><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Jan 16, 2016 at 8:28 AM, Nate Cook <span dir="ltr"><<a href="mailto:natecook@gmail.com" target="_blank">natecook@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div>Adding a `combine` closure with Donnacha's default seems like a pretty good solution for this, but giving a `try`-marked closure parameter a default messes with the rethrows behavior and requires a try on every call. I think it's important that when used by default, this initializer has the same behavior as looping over the sequence and setting values for keys. That is, it should replicate:</div><span><div><br></div><div>for (key, value) in sequence { </div></span><div> newDictionary[key] = value </div><div>}</div><div><br></div><div>and use the last value for any duplicate keys, rather than failing or trapping.</div><div><br></div><div>To handle this properly we'd need two new initializers:</div><div><br></div><div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:#bb2ca2">init</span><span style="color:#000000"><S: </span>SequenceType<span style="color:#000000"> </span><span style="color:#bb2ca2">where</span><span style="color:#000000"> </span>S<span style="color:#000000">.</span>Generator<span style="color:#000000">.</span>Element<span style="color:#000000"> == </span>Generator<span style="color:#000000">.</span>Element<span style="color:#000000">>(</span><span style="color:#bb2ca2">_</span><span style="color:#000000"> sequence: </span>S<span style="color:#000000">)</span></div></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:#000000"><br></span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span><div style="margin:0px;line-height:normal"><span style="color:#bb2ca2">init</span><S: SequenceType <span style="color:#bb2ca2">where</span> S.Generator.Element == Generator.Element></div></span><div style="margin:0px;line-height:normal"> (<span style="color:#bb2ca2">_</span> sequence: S, <span style="color:#bb2ca2">@noescape</span> combine: (Value, Value) <span style="color:#bb2ca2">throws</span> -> Value) <span style="color:#bb2ca2">rethrows</span></div><div><br></div></div><div>Perhaps we also need a mutating `mergeContentsOf` function with the same signatures as the initializers:</div><div><br></div><div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:#bb2ca2">mutating</span><span style="color:#000000"> </span><span style="color:#bb2ca2">func</span><span style="color:#000000"> mergeContentsOf<S: </span>SequenceType<span style="color:#000000"> </span><span style="color:#bb2ca2">where</span><span style="color:#000000"> </span>S<span style="color:#000000">.</span>Generator<span style="color:#000000">.</span>Element<span style="color:#000000"> == </span>Generator<span style="color:#000000">.</span>Element<span style="color:#000000">>(</span><span style="color:#bb2ca2">_</span><span style="color:#000000"> sequence: </span>S<span style="color:#000000">)</span></div></div><div><span style="color:#000000"><br></span></div><div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:#bb2ca2">mutating</span> <span style="color:#bb2ca2">func</span> mergeContentsOf<S: <span style="color:#703daa">SequenceType</span> <span style="color:#bb2ca2">where</span> S.Generator.Element == <span style="color:#703daa">Generator</span>.Element></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"> (<span style="color:#bb2ca2">_</span> sequence: S, <span style="color:#bb2ca2">@noescape</span> combine: (Value, Value) <span style="color:#bb2ca2">throws</span> -> Value) <span style="color:#bb2ca2">rethrows</span></div></div><div><span style="color:#bb2ca2"><br></span></div><div>I'm pretty sure I would use all four of those, and that would bring Dictionary more into alignment with how you can use Array and Set. Would a slightly expanded proposal make sense?</div><span><font color="#888888"><div><br></div>Nate<div><br></div></font></span><div><br><div><blockquote type="cite"><div><div><div>On Jan 15, 2016, at 9:01 AM, Nicola Salmoria via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:</div><br></div></div><div><div><div><div dir="ltr" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div>I'm ambivalent about the preconditionFailure. Since there would otherwise be silent loss of data, I think it fits Swift's "safe by default" paradigm. It's also consistent with what the normal initialization from a DictionaryLiteral does.<br></div><div>However, I can also see how it might be more convenient to just pick the last value.<br></div><br>Nicola<br><br><div><div class="gmail_extra"><div class="gmail_quote">On Fri, Jan 15, 2016 at 11:53 AM, Alan Skipp<span> </span><span dir="ltr"><<a href="mailto:al_skipp@icloud.com" target="_blank">al_skipp@icloud.com</a>></span><span> </span>wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word">I’ve been absorbed in the world of Monoids lately, so I find the suggestion below to be particularly brilliant. : )<div>It solves the issue of arbitrarily choosing the value for duplicate keys rather nicely. Only thing I’m not too sure about is the idea of failing by default on duplicate keys?</div><div><br></div><div><div><span><div><blockquote type="cite"><div>On 15 Jan 2016, at 10:18, Nicola Salmoria via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:</div><br><div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">To handle the case of duplicate keys, why not allow to pass in a 'combine' function?<br>The function could default to a preconditionFailure to be consistent with the DictionaryLiteral behavior, but be overridden by the caller as needed.<br><br>extension Dictionary {<br> <span> </span>/// Creates a dictionary with the keys and values in the given sequence.<br> <span> </span>init<S: SequenceType where S.Generator.Element == Generator.Element>(_ sequence: S, combine: (existing: Value, other: Value) -> Value = { preconditionFailure("Sequence contains duplicate keys"); return $1 } ) {<br> <span> </span>self.init()<br> <span> </span>for (key, value) in sequence {<br> <span> </span>if let existing = updateValue(value, forKey: key) {<br> <span> </span>updateValue(combine(existing: existing, other: value), forKey: key)<br> <span> </span>}<br> <span> </span>}<br> <span> </span>}<br>}<br><br><br>usage examples:<br><br>let samples = [("Rome", 40.2), ("New York", 35.1), ("Rome", 42.5), ("New York", 32.8)]<br>let minTemperatures = Dictionary(samples, combine: min)<br>// ["Rome": 40.2, "New York": 32.8]<br>let maxTemperatures = Dictionary(samples, combine: max)<br>// ["Rome": 42.5, "New York": 35.1]<br><br>let probabilities = [("a", 0.25), ("b", 0.25), ("c", 0.25), ("a", 0.25)]<br>let stateProbabilities = Dictionary(probabilities, combine: +)<br>// ["b": 0.25, "a": 0.5, "c": 0.25]<br><br></div><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">Nicola</span></div></blockquote><br></div></span><div><div>It’d be great if there was also an init that restricted the Values to Monoids, which would mean the combine function would be taken from the supplied Monoid values (I understand I’ve departed to fantasy island at this point, but one can dream : )</div><div><br></div><div>Al<br></div><div><br></div></div><br></div></div></div></blockquote></div><br></div></div></div></div></div><span><img src="https://u2002410.ct.sendgrid.net/wf/open?upn=4GlEpM11j-2BGED-2FudNhzzUKGouoeTKtIEqwsP-2B6t6Pznw62fwc6eD7hA5jHkKPGv4C1Yq7IFXDogBVK-2Fqbt3p1fwf4Dk4iN5FsHRZphL81XTPbkyTzEb8nG6B9kzZObH1DUzAG7RTdq79UTGxXqQ5kCTJgqWs6-2FOahACF007ATtJPwyHmkUUF0F38iT97HDxQ-2FZrWLxJKMGL9PN2Q0Gnjy-2BvGb-2B5uou9LRqIjke0uoUU-3D" alt="" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;min-height:1px!important;width:1px!important;border-width:0px!important;margin:0px!important;padding:0px!important" width="1" height="1" border="0"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important"><span> </span>_______________________________________________</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">swift-evolution mailing list</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><a href="mailto:swift-evolution@swift.org" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" target="_blank">swift-evolution@swift.org</a><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a></span></div></blockquote></div><br></div></div></blockquote></div><br></div>
</div></blockquote><blockquote type="cite"><div><span>_______________________________________________</span><br><span>swift-evolution mailing list</span><br><span><a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a></span><br><span><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a></span><br></div></blockquote></div></div></div><br>_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
<br></blockquote></div><br></div>