<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 Aug 17, 2017, at 10:05 AM, Erica Sadun via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Also, for those of you here who haven't heard my previous rant on the subject, I dislike using map for generating values that don't depend on transforming a domain to a range. (It has been argued that `_ in` is mapping from `Void`, but I still dislike it immensely)</div></div></div></blockquote><div><br class=""></div><div>Can you please elaborate why (or maybe point me at the rant)? Does the same argument apply to `for _ in 1..&lt;N { … }`?</div><div><br class=""></div><div>But back to the discussion. I quickly looked at the sil being generated, and measured the performance of:</div><div><br class=""></div><div><div>public class C {</div><div>&nbsp; init() {}</div><div>}</div><div><br class=""></div><div>@inline(never)</div><div>func foo(n: Int) -&gt; [C] {</div><div>&nbsp; var result: [C] = []</div><div>&nbsp; result.reserveCapacity(n)</div><div>&nbsp; for _ in 1...n {</div><div>&nbsp; &nbsp; result.append(C())</div><div>&nbsp; }</div><div>&nbsp; return result</div><div>}</div><div><br class=""></div><div>@inline(never)</div><div>func bar(n: Int) -&gt; [C] {</div><div>&nbsp; return (1...n).map { _ in C() }</div><div>}</div><div class=""><br class=""></div><div class="">Version using map wins in both the size of sil and performance. It is also easier to implement right (fewer moving parts, I guess). If one forgets to call `reserveCapacity` on `result` in the first case, performance drops even further.</div><div class=""><br class=""></div><div class="">Max</div></div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""></div><div class="">Here are the ways that I have approached this:</div><div class=""><br class=""></div><div class=""><div class="">// Ugh</div><div class="">[UIView(), UIView(), UIView(), UIView(), UIView()]</div><div class=""><br class=""></div><div class="">// No:</div><div class="">let viewsA = Array(repeating: UIView(), count: 5)&nbsp;</div><div class="">// You end up with 5 of the same view</div></div><div class=""><br class=""></div><div class=""><div class="">// Two statements that really should be one</div><div class=""><div class="">var views: [UIView] = []</div><div class="">for _ in 1 ... 5 { views.append(UIView()) }</div></div><div class=""><br class=""></div><div class="">// Wrong use of `map`, &nbsp;because it's mapping over `Void`</div><div class="">let viewsA = (1 ... 5).map({ _ in UIView() })&nbsp;</div><div class=""><br class=""></div><div class=""><div class="">// You can introduce `collect` specifically for the `_ in` in case, matching other languages:</div><div class="">public func collect&lt;T&gt;(_ generator: () throws -&gt; T) rethrows -&gt; [T]</div><div class=""><br class=""></div></div></div><div class="">// I think these are just ugly</div><div class=""><div class="">let viewsA__ = sequence(first: UIView(), next: { _ in UIView() }).lazy.prefix(5)</div></div><div class="">let viewsB__ = sequence(state: 5, next: { defer { $0 -= 1 }; $0 == 0 ? nil : UIView() }</div><div class=""><br class=""></div><div class="">// You can build an iterator</div><div class=""><br class=""></div><div class=""><div class="">let labeler = AnyIterator({ return UILabel() })</div><div class="">let labels4 = Array(labeler.prefix(5))</div></div><div class=""><br class=""></div><div class="">// which lets you create multiple "slices" off the iterator</div><div class=""><br class=""></div><div class=""><div class="">let randoms = AnyIterator({ return Int(arc4random_uniform(100) )})</div><div class=""><br class=""></div><div class="">print(Array(randoms.prefix(5)))</div><div class="">print(Array(randoms.prefix(5)))</div></div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><div class="">// A little complex and I don't like making this `Int` based, because it pulls the semantics away from sequences/collections</div><div class=""><br class=""></div><div class="">extension Int {</div><div class="">&nbsp; &nbsp; func of&lt;T&gt;(_ generator: @autoclosure () -&gt; T) -&gt; [T] {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; assert(self &gt;= 0, "cannot generate negative-count collection")</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; return (0 ..&lt; self).map({ _ in generator() })</div><div class="">&nbsp; &nbsp; }</div><div class="">}</div><div class=""><br class=""></div><div class="">5.of(UIView())</div></div><div class=""><br class=""></div><div class="">// Even worse</div><div class=""><div class="">protocol Constructable {</div><div class="">&nbsp; &nbsp; init()</div><div class="">}</div><div class=""><br class=""></div><div class="">extension UIView: Constructable {}</div><div class=""><br class=""></div><div class="">extension Int {</div><div class="">&nbsp; &nbsp; func of&lt;T: Constructable&gt;(_ generator: @autoclosure () -&gt; T) -&gt; UnfoldSequence&lt;T, Int&gt; {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; assert(self &gt; 0, "cannot generate negative-count collection")</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; return sequence(state: self, next: { (state: inout Int) -&gt; T? in</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; defer { state -= 1 }; return state == 0 ? nil : T.init() })</div><div class="">&nbsp; &nbsp; }</div><div class="">}</div><div class=""><br class=""></div><div class="">print(Array(5.of(UIView())))</div></div><div class=""><br class=""></div><div class="">// or</div><div class=""><br class=""></div><div class=""><div class="">extension Int {</div><div class="">&nbsp; &nbsp; func of&lt;T&gt;(_ generator: @escaping @autoclosure () -&gt; T) -&gt; LazyMapRandomAccessCollection&lt;(CountableRange&lt;Int&gt;), T&gt; {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; assert(self &gt; 0, "cannot generate negative-count collection")</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; return (0 ..&lt; self).lazy.map({ _ in generator() })</div><div class="">&nbsp; &nbsp; }</div><div class="">}</div></div><div class=""><br class=""></div><div class="">// where some people preferred calling this `elements`, for example `5.elements(of: UIView())`</div><div class=""><br class=""></div><div class="">// You can go Array:</div><div class=""><br class=""></div><div class=""><div class="">extension Array {</div><div class="">&nbsp; &nbsp; /// Creates a new array containing the specified number of values created by repeating a generating closure.</div><div class="">&nbsp; &nbsp; ///</div><div class="">&nbsp; &nbsp; /// - Parameters:</div><div class="">&nbsp; &nbsp; /// &nbsp; - count: The number of times to apply the closure. `count` must be zero or greater.</div><div class="">&nbsp; &nbsp; /// &nbsp; - generator: The closure to execute</div><div class="">&nbsp; &nbsp; public init(count: Int, repeating: () -&gt; Element) {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; precondition(count &gt;= 0, "")</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; self.init((1 ... count).map({ _ in repeating() }))</div><div class="">&nbsp; &nbsp; }</div><div class="">}</div><div class=""><br class=""></div><div class="">let labels = Array(count: 4) { UILabel() }</div></div><div class=""><br class=""></div><div class="">// Or similarly</div><div class=""><br class=""></div><div class=""><div class="">extension Array {</div><div class=""><div class="">&nbsp; &nbsp; init(repeat count: Int, byCalling generator: @autoclosure () -&gt; Element) {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; self = (1 ... count).map({ _ in generator() })</div><div class="">&nbsp; &nbsp; }</div><div class="">}</div></div><div class=""><br class=""></div><div class=""><div class="">// From Oliver H:</div><div class=""><br class=""></div><div class=""><div class="">extension Array {</div><div class="">&nbsp; convenience init(count: Int, repeating: () -&gt; Elements) {</div><div class="">&nbsp; &nbsp; self = Array( (0..&lt;count).map { _ in repeating() } )</div><div class="">&nbsp; }</div><div class="">}</div></div><div class=""><br class=""></div><div class="">let views: [UIView] = Array(count: 5) { UIView(frame: .zero) }</div></div><div class=""><br class=""></div><div class="">// This one is from Soroush K. I think it's clever but I wouldn't really use it</div></div><div class=""><br class=""></div><div class=""><div class="">func * &lt;T&gt;(generator: @autoclosure () -&gt; T, n: Int) -&gt; [T] {</div><div class="">&nbsp; (0..&lt;n).map({ _ in generator() }</div><div class="">}</div></div><div class=""><br class=""></div><div class="">UIView() * 5</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On Aug 17, 2017, at 10:36 AM, Tony Allevato via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><br class=""><br class=""><div class="gmail_quote"><div dir="ltr" class="">On Thu, Aug 17, 2017 at 9:20 AM Ross O'Brien &lt;<a href="mailto:narrativium%2Bswift@gmail.com" class="">narrativium+swift@gmail.com</a>&gt; wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="">(0..&lt;3).map{ _ in UIView() } - map already returns an Array.<div class=""><br class=""><div class="">Array((0..&lt;3).map{ _ in UIView() }) is redundant.</div></div></div></blockquote><div class=""><br class=""></div><div class="">Ah, right, thanks for pointing that out. I couldn't remember off the top of my head whether it returned an array or some kind of special sequence type that would need to be converted over.</div><div class=""><br class=""></div><div class="">In that case, I still think the map version wins—it's very clear that a repeated *operation* is occurring, whereas the originally proposed @autoclosure version hides that very important semantic information.</div><div class=""><br class=""></div><div class=""><br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class=""><div class="">I've fallen foul before, of trying to create an array of six buttons and getting an array of one button six times; I think that should be easier. But if each button corresponds to an existing value or needs to be initialised based on its index in that array, map transposing values or indices into buttons is already covered.<br class=""></div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Thu, Aug 17, 2017 at 5:03 PM, Tony Allevato via swift-evolution <span dir="ltr" class="">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt;</span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="">Couldn't this be rewritten more simply today as:<div class=""><br class=""></div><div class="">&nbsp; &nbsp; Array((0..&lt;3).map { index in MyView(forIndex: index) })</div><div class=""><br class=""></div><div class="">And the version that doesn't need the index could be written:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; Array((0..&lt;3).map { _ in UIView() })</div><div class=""><br class=""></div><div class="">The AnyIterator approach posted above is also nice—I wouldn't have thought of that one. But I suppose that only works in the case where you don't need the index.</div><div class=""><br class=""></div><div class="">So the question is, should we increase the API surface of Array for something that (IMO) is already fairly straightforward to do? The nice thing about the approaches above is that they're composable. Array doesn't have to make any assumptions about closures or index arguments to those closures; it just takes a sequence and we already have primitives to construct sequences of new objects using .map. Array(repeating:count:) and repeatedElement(_:count:) are nice when the value being repeated is fixed, but I think once you start getting into questions like "what if I need a different thing each time?" or "what if I need to involve the index as part of the elements?" then it's better suited to compose the features already there to build something up than to add new APIs that try to cover each of these special cases.</div><div class=""><br class=""></div></div><div class="m_-3910698560844300130HOEnZb"><div class="m_-3910698560844300130h5"><br class=""><div class="gmail_quote"><div dir="ltr" class="">On Thu, Aug 17, 2017 at 8:40 AM Christopher Kornher via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt; wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class=""><div class="">We might as well add the index to the call so elements can be created from other lists, etc.</div><div class=""><br class=""></div><div class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class="">&nbsp;Array(repeatedlyCalling: { (index:Int) in MyView( forIndex:index ) }, count: 3) // This might by syntactically correct...</div></div></div></div></div></div><div style="word-wrap:break-word" class=""><div class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class=""><br class=""></div></div></div></div></div><div class=""><br class=""></div><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Aug 17, 2017, at 9:24 AM, Rob Mayoff via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="m_-3910698560844300130m_7752994478503109029m_-6561560767473454887Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote">On Thu, Aug 17, 2017 at 7:04 AM, Robert Bennett via swift-evolution <span dir="ltr" class="">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt;</span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto" class=""><div class=""></div><div class="">Alternatively, instead of replacing the current definition with an autoclosure version, we could leave the current version in place and add a version taking a function. This could be especially useful when you’ve defined a function like `makeMySpecialKindOfButton() -&gt; UIButton` that does a lot of customization to an object before returning it.</div><div class=""><br class=""></div><div class="">Array(repeating: { return UIView() }, count: 3)</div><div class="">and</div><div class="">Array(repeating: <span style="background-color:rgba(255,255,255,0)" class="">makeMySpecialKindOfButton, count: 3)</span></div></div></blockquote><div class=""><br class=""></div><div class="">This is still source-breaking, because an array of closures is legal. We need a different name to avoid breaking source:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; Array(repeatedlyCalling: { UIView() }, count: 3)</div><div class="">&nbsp;</div></div></div></div>
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></blockquote></div><br class=""></div>_______________________________________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
</blockquote></div>
</div></div><br class="">_______________________________________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
<br class=""></blockquote></div><br class=""></div>
</blockquote></div></div>
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></blockquote></div><br class=""></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></body></html>