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)

Here are the ways that I have approached this:

// Ugh
[UIView(), UIView(), UIView(), UIView(), UIView()]

// No:
let viewsA = Array(repeating: UIView(), count: 5) 
// You end up with 5 of the same view

// Two statements that really should be one
var views: [UIView] = []
for _ in 1 ... 5 { views.append(UIView()) }

// Wrong use of `map`,  because it's mapping over `Void`
let viewsA = (1 ... 5).map({ _ in UIView() }) 

// You can introduce `collect` specifically for the `_ in` in case, matching 
other languages:
public func collect<T>(_ generator: () throws -> T) rethrows -> [T]

// I think these are just ugly
let viewsA__ = sequence(first: UIView(), next: { _ in UIView() }).lazy.prefix(5)
let viewsB__ = sequence(state: 5, next: { defer { $0 -= 1 }; $0 == 0 ? nil : 
UIView() }

// You can build an iterator

let labeler = AnyIterator({ return UILabel() })
let labels4 = Array(labeler.prefix(5))

// which lets you create multiple "slices" off the iterator

let randoms = AnyIterator({ return Int(arc4random_uniform(100) )})

print(Array(randoms.prefix(5)))
print(Array(randoms.prefix(5)))


// A little complex and I don't like making this `Int` based, because it pulls 
the semantics away from sequences/collections

extension Int {
    func of<T>(_ generator: @autoclosure () -> T) -> [T] {
        assert(self >= 0, "cannot generate negative-count collection")
        return (0 ..< self).map({ _ in generator() })
    }
}

5.of(UIView())

// Even worse
protocol Constructable {
    init()
}

extension UIView: Constructable {}

extension Int {
    func of<T: Constructable>(_ generator: @autoclosure () -> T) -> 
UnfoldSequence<T, Int> {
        assert(self > 0, "cannot generate negative-count collection")
        return sequence(state: self, next: { (state: inout Int) -> T? in
            defer { state -= 1 }; return state == 0 ? nil : T.init() })
    }
}

print(Array(5.of(UIView())))

// or

extension Int {
    func of<T>(_ generator: @escaping @autoclosure () -> T) -> 
LazyMapRandomAccessCollection<(CountableRange<Int>), T> {
        assert(self > 0, "cannot generate negative-count collection")
        return (0 ..< self).lazy.map({ _ in generator() })
    }
}

// where some people preferred calling this `elements`, for example 
`5.elements(of: UIView())`

// You can go Array:

extension Array {
    /// Creates a new array containing the specified number of values created 
by repeating a generating closure.
    ///
    /// - Parameters:
    ///   - count: The number of times to apply the closure. `count` must be 
zero or greater.
    ///   - generator: The closure to execute
    public init(count: Int, repeating: () -> Element) {
        precondition(count >= 0, "")
        self.init((1 ... count).map({ _ in repeating() }))
    }
}

let labels = Array(count: 4) { UILabel() }

// Or similarly

extension Array {
    init(repeat count: Int, byCalling generator: @autoclosure () -> Element) {
        self = (1 ... count).map({ _ in generator() })
    }
}

// From Oliver H:

extension Array {
  convenience init(count: Int, repeating: () -> Elements) {
    self = Array( (0..<count).map { _ in repeating() } )
  }
}

let views: [UIView] = Array(count: 5) { UIView(frame: .zero) }

// This one is from Soroush K. I think it's clever but I wouldn't really use it

func * <T>(generator: @autoclosure () -> T, n: Int) -> [T] {
  (0..<n).map({ _ in generator() }
}

UIView() * 5


> On Aug 17, 2017, at 10:36 AM, Tony Allevato via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> 
> 
> On Thu, Aug 17, 2017 at 9:20 AM Ross O'Brien <narrativium+sw...@gmail.com 
> <mailto:narrativium%2bsw...@gmail.com>> wrote:
> (0..<3).map{ _ in UIView() } - map already returns an Array.
> 
> Array((0..<3).map{ _ in UIView() }) is redundant.
> 
> 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.
> 
> 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.
> 
> 
> 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.
> 
> On Thu, Aug 17, 2017 at 5:03 PM, Tony Allevato via swift-evolution 
> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
> Couldn't this be rewritten more simply today as:
> 
>     Array((0..<3).map { index in MyView(forIndex: index) })
> 
> And the version that doesn't need the index could be written:
> 
>     Array((0..<3).map { _ in UIView() })
> 
> 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.
> 
> 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.
> 
> 
> On Thu, Aug 17, 2017 at 8:40 AM Christopher Kornher via swift-evolution 
> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
> We might as well add the index to the call so elements can be created from 
> other lists, etc.
> 
>  Array(repeatedlyCalling: { (index:Int) in MyView( forIndex:index ) }, count: 
> 3) // This might by syntactically correct...
> 
> 
> 
>> On Aug 17, 2017, at 9:24 AM, Rob Mayoff via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> On Thu, Aug 17, 2017 at 7:04 AM, Robert Bennett via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 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() -> UIButton` that does 
>> a lot of customization to an object before returning it.
>> 
>> Array(repeating: { return UIView() }, count: 3)
>> and
>> Array(repeating: makeMySpecialKindOfButton, count: 3)
>> 
>> This is still source-breaking, because an array of closures is legal. We 
>> need a different name to avoid breaking source:
>> 
>>     Array(repeatedlyCalling: { UIView() }, count: 3)
>>  
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to