<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On 31 Oct 2016, at 05:15, Dave Abrahams &lt;<a href="mailto:dabrahams@apple.com" class="">dabrahams@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">on Sun Oct 30 2016, Karl &lt;</span><a href="http://razielim-at-gmail.com/" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">razielim-AT-gmail.com</a><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">&gt; wrote:</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class="">On 30 Oct 2016, at 19:23, Dave Abrahams via swift-users &lt;<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>&gt; wrote:<br class=""><br class=""><br class="">on Sun Oct 30 2016, Karl &lt;<a href="http://swift-users-AT-swift.org" class="">swift-users-AT-swift.org</a>&gt; wrote:<br class=""><br class=""></blockquote><br class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><blockquote type="cite" class="">On 30 Oct 2016, at 09:15, Karl &lt;<a href="mailto:raziel.im+swift-users@gmail.com" class="">raziel.im+swift-users@gmail.com</a>&gt; wrote:<br class=""><br class="">I had the need for a concurrent map recently. I had a part of a<br class="">program which needed to read chunks of data and concurrently process<br class="">them and assemble the results in an array. This isn’t necessarily as<br class="">obvious as it sounds, because of arrays being value types. I came up<br class="">with the following snippet which I’d like to check for correctness;<br class="">it could also be helpful to others.<br class=""><br class="">Perhaps this is something Dispatch should provide out-of-the-box?<br class=""><br class="">- Karl<br class=""></blockquote><br class="">Ah one second, I was refactoring this and forgot to test it. Here’s the actual code:<br class=""></blockquote><br class="">A map presumably requires an input<span class="Apple-converted-space">&nbsp;</span><br class=""></blockquote><br class="">DispatchQueue.concurrentMap maps a Range&lt;Int&gt; -&gt; T, but since the<br class="">range is always 0..&lt;n, we only ask for the value of n. It could also<br class="">be written quite naturally as an extension on Range and build<br class="">everything on top of it.<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Sorry, I wrote “a map presumably requires an input” before I realized</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">what you were doing. &nbsp;I should have deleted that.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><br class=""><blockquote type="cite" class="">extension DispatchQueue {<br class=""><br class="">static func concurrentMap&lt;T&gt;(iterations: Int, execute block: (Int) -&gt; T) -&gt; [T] {<br class=""><br class="">&nbsp;&nbsp;let __result = UnsafeMutableRawBufferPointer.allocate(count: iterations * MemoryLayout&lt;T&gt;.stride)<br class="">&nbsp;&nbsp;defer { __result.deallocate() }<br class="">&nbsp;&nbsp;let _result &nbsp;= __result.baseAddress?.assumingMemoryBound(to: T.self)<br class=""></blockquote><br class="">You never bound the memory to T, so this will be undefined behavior. &nbsp;<br class=""><br class=""><blockquote type="cite" class="">&nbsp;&nbsp;let result &nbsp;&nbsp;= UnsafeMutableBufferPointer&lt;T&gt;(start: _result, count: iterations)<br class="">&nbsp;&nbsp;concurrentPerform(iterations: iterations) { idx in<br class="">&nbsp;&nbsp;&nbsp;&nbsp;result[idx] = block(idx)<br class=""></blockquote><br class="">You also never initialized the Ts in that memory region, so assigning<br class="">into them will also be undefined behavior.<br class=""><br class=""><blockquote type="cite" class="">&nbsp;&nbsp;}<br class="">&nbsp;&nbsp;return Array(result)<br class="">}<br class="">}<br class=""><br class="">extension Array {<br class="">func concurrentMap&lt;T&gt;(execute block: (Element)-&gt;T) -&gt; [T] {<br class="">&nbsp;&nbsp;return DispatchQueue.concurrentMap(iterations: count) { block(self[$0]) }<br class="">}<br class="">}<br class=""><br class="">Unfortunately I don’t think there’s a way to get an array to take over a +1<br class="">UnsafeMutableBufferPointer without copying.<br class=""></blockquote><br class="">The only correct way to do this without creating intermediate storage is<br class="">to have a way to initialize your result elements, e.g.:<br class=""><br class="">import Dispatch<br class=""><br class="">protocol DefaultInitializable {<br class="">&nbsp;&nbsp;init()<br class="">}<br class=""><br class="">extension RandomAccessCollection {<br class="">&nbsp;&nbsp;func concurrentMap&lt;T&gt;(_ transform: (Iterator.Element)-&gt;T) -&gt; [T]<br class="">&nbsp;&nbsp;where T : DefaultInitializable {<br class="">&nbsp;&nbsp;&nbsp;&nbsp;var result = Array(<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;repeating: T(), count: numericCast(self.count))<br class=""><br class="">&nbsp;&nbsp;&nbsp;&nbsp;DispatchQueue.concurrentPerform(iterations: result.count) {<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offset in<span class="Apple-converted-space">&nbsp;</span><br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result[offset] = transform(<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self[index(startIndex, offsetBy: numericCast(offset))])<br class="">&nbsp;&nbsp;&nbsp;&nbsp;}<br class="">&nbsp;&nbsp;&nbsp;&nbsp;return result<br class="">&nbsp;&nbsp;}<br class="">}<br class=""><br class="">extension Int : DefaultInitializable { &nbsp;}<br class=""><br class="">print((3..&lt;20).concurrentMap { $0 * 2 })<br class=""><br class=""></blockquote><br class="">I had a go at doing that before, using Optional&lt;T&gt; and unwrapping at<br class="">the end — but it occurred to me that it would be very inefficient for<br class="">things like Optional&lt;Int&gt;, and introduces more allocations.<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Yeah, optional is not really a good choice for that application.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class="">If you don't want the DefaultInitializable requirement (or some other<br class="">way to prepare initialized elements), you'll need to manage memory<br class="">yourself:<br class=""><br class="">extension RandomAccessCollection {<br class="">&nbsp;&nbsp;func concurrentMap&lt;T&gt;(_ transform: (Iterator.Element)-&gt;T) -&gt; [T] {<br class="">&nbsp;&nbsp;&nbsp;&nbsp;let n = numericCast(self.count) as Int<br class="">&nbsp;&nbsp;&nbsp;&nbsp;let p = UnsafeMutablePointer&lt;T&gt;.allocate(capacity: n)<br class="">&nbsp;&nbsp;&nbsp;&nbsp;defer { p.deallocate(capacity: n) }<br class=""><br class="">&nbsp;&nbsp;&nbsp;&nbsp;DispatchQueue.concurrentPerform(iterations: n) {<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offset in<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(p + offset).initialize(<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;to: transform(<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self[index(startIndex, offsetBy: numericCast(offset))]))<br class="">&nbsp;&nbsp;&nbsp;&nbsp;}<br class=""><br class="">&nbsp;&nbsp;&nbsp;&nbsp;return Array(UnsafeMutableBufferPointer(start: p, count: n))<br class="">&nbsp;&nbsp;}<br class="">}<br class=""><br class="">This posting highlights a couple of weaknesses in the standard library<br class="">for which I'd appreciate bug reports:<br class=""><br class="">1. No way to arbitrarily initialize an Array's storage.<br class="">2. UnsafeMutableBufferPointer doesn't have an allocating init<br class=""><br class=""></blockquote>Filed:<br class=""><br class="">1.<span class="Apple-converted-space">&nbsp;</span><a href="https://bugs.swift.org/browse/SR-3087" class="">https://bugs.swift.org/browse/SR-3087</a><br class="">2.<span class="Apple-converted-space">&nbsp;</span><a href="https://bugs.swift.org/browse/SR-3088" class="">https://bugs.swift.org/browse/SR-3088</a><br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Thanks for these!</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class=""><br class="">What is your opinion on the corelibs extending the standard library<br class="">types?<span class="Apple-converted-space">&nbsp;</span><br class="">Foundation does it to provide APIs from NSString, but it’s kind of a<br class="">special case.<span class="Apple-converted-space">&nbsp;</span><br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">My opinion is that, *as a rule*, frameworks should avoid extending APIs</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">from other frameworks; it makes it very hard for the author of the</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">original type to manage the user experience of her type. &nbsp;But there are</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">exceptions to every rule ;-)</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">Would it be reasonable for Dispatch (which is not _such_ a special<br class="">case) to also extend types like Range and Collection?<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Oh, well now *Collection* is not a type (despite how it's defined in the</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">language); it's a protocol. &nbsp;Extending Collection is the best way to</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">write generic algorithms over all Collections, so I support that. &nbsp;But</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">it does have to be done very judiciously, because you have to realize</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">the API you are providing is going to appear on everything that conforms</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">to Collection.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">I quite like the API as an extension on Range. I think it would be a<br class="">nice addition to Dispatch (once we start allowing additive proposals):<br class=""><br class="">extension Range where Bound : Strideable, Bound.Stride : SignedInteger {<br class=""><br class="">&nbsp;func concurrentMap&lt;T&gt;(_ transform: (Bound) -&gt; T) -&gt; [T] {<br class="">&nbsp;&nbsp;&nbsp;let n &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= numericCast(count) as Int<br class="">&nbsp;&nbsp;&nbsp;let buffer = UnsafeMutablePointer&lt;T&gt;.allocate(capacity: n)<br class=""><br class="">&nbsp;&nbsp;&nbsp;DispatchQueue.concurrentPerform(iterations: n) {<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(buffer + $0).initialize(to: transform(lowerBound + numericCast($0)))<br class="">&nbsp;&nbsp;&nbsp;}<br class=""><br class="">&nbsp;&nbsp;&nbsp;// Unfortunately, the buffer is copied when making it an Array&lt;T&gt;.<br class="">&nbsp;&nbsp;&nbsp;defer { buffer.deallocate(capacity: n) }<br class="">&nbsp;&nbsp;&nbsp;return Array(UnsafeMutableBufferPointer&lt;T&gt;(start: buffer, count: n))<br class="">&nbsp;}<br class="">}<br class=""><br class="">extension Collection {<br class="">&nbsp;func concurrentMap&lt;T&gt;(_ transform: (Iterator.Element)-&gt;T) -&gt; [T] {<br class=""><br class="">&nbsp;&nbsp;&nbsp;// ‘as Range’ because CountableRange is a collection, causing the function to be recursive.<br class="">&nbsp;&nbsp;&nbsp;return ((0..&lt;numericCast(count)) as Range).concurrentMap {<br class="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;transform(self[index(startIndex, offsetBy: numericCast($0))])<br class="">&nbsp;&nbsp;&nbsp;}<br class="">&nbsp;}<br class="">}<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">I see the beauty in what you're doing here, but I don't see any</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">advantage to it for users. &nbsp;Now Range (which will be collapsed with</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">CountableRange in Swift 4) will have two overloads of concurrentMap. &nbsp;In</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">general, avoidable overloads are bad for the user experience.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">HTH,</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">--<span class="Apple-converted-space">&nbsp;</span></span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">-Dave</span></div></blockquote><br class=""></div><div>Notwithstanding your comment about `collection.parallel.map { }.filter {}`, the issue here is with the literal being interpreted as CountableRange. That can be really annoying in general, and I’m glad the different Range types are going away.</div><div><br class=""></div><div>If Range conditionally conforms to Collection (say, when its Bound is Strideable), then `(0..&lt;5).concurrentMap {}` should still call the function on Range because it’s “more specialised”, isn't that correct?</div><div><br class=""></div><div>Thanks</div><div><br class=""></div><div>- Karl</div><br class=""></body></html>