On Thu, Aug 17, 2017 at 9:06 PM, Erica Sadun via swift-evolution <
swift-evolution@swift.org> wrote:

>
> On Aug 17, 2017, at 6:56 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote:
>
> On Thu, Aug 17, 2017 at 7:51 PM, Erica Sadun <er...@ericasadun.com> wrote:
>
>> What people are doing is taking a real set of values (1, 2, 3, 4, 5, for
>> example), then discarding them via `_ in`, which is different from `Void ->
>> T` or `f(x) = 0 * x`. The domain could just as easily be (Foo(), "b", đź’©,
>>  UIColor.red, { x: Int in x^x }). There are too many semantic shifts away
>> from "I would like to collect the execution of this closure n times" for it
>> to sit comfortably.
>>
>
> What arguments might help to alleviate this discomfort? Clearly, functions
> exist that can map this delightfully heterogeneous domain to some sort of
> range that the user wants. Would you feel better if we wrote instead the
> following?
>
> ```
> repeatElement((), count: 5).map { UIView() }
> ```
>
>
> My favorite solution is the array initializer. Something along the lines
> of `Array<T>(count n: Int, generator: () -> T)`. I'm not sure it _quite_
> reaches standard library but I think it is a solid way to say "produce a
> collection with a generator run n times". It's a common  task. I was asking
> around about this, and found that a lot of us who work with both macOS and
> iOS and want to stress test interfaces do this very often. Other use cases
> include "give me n random numbers", "give me n records from this database",
> etc. along similar lines.
>
> The difference between this and the current `Array(repeating:count:)`
> initializer is switching the arguments and using a trailing closure  (or an
> autoclosure) rather than a set value. That API was designed without the
> possibility that you might want to repeat a generator, so there's a bit of
> linguistic turbulence.
>
> -- E
>
>
To me at least, this is a very i-Centric complaint, since I can barely
remember the last time I needed something like this for anything that
didn’t involve UIKit. What you’re asking for is API sugar for generating
reference types with less typing. The problem is it’s hugely disruptive to
user’s mental model of how Swift operates, to say the least. When I read a
function signature like Array.init(count:object:) or whatever, I expect
that if a referency type is passed to the object parameter, the *pointer*
gets copied `count` times, and the reference count incremented accordingly.
I don’t expect the object itself to get deepcopied. That’s why the use of
@autoclosure is strongly recommended against
<https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=5&cad=rja&uact=8&ved=0ahUKEwjar8qe6d_VAhUC4YMKHcIIC5MQygQIRDAE&url=https%3A%2F%2Fdeveloper.apple.com%2Flibrary%2Fcontent%2Fdocumentation%2FSwift%2FConceptual%2FSwift_Programming_Language%2FClosures.html%23%2F%2Fapple_ref%2Fdoc%2Fuid%2FTP40014097-CH11-ID543&usg=AFQjCNHnH4tzGagCKcjU5jRzK-GSDCB6qA>,
and why it only appears in things relating to debugging like
assert(condition:message:file:line:), which are mentally separated from the
rest of Swift.

Doing this with a function is less disruptive, but if you ask me, it
expands API surface area without offering any real benefit. As people have
pointed out, we already have a perfectly good idiom in (0 ..< n).map{ _ in
UIView() }. I never understood why certain people complain about
“discarding the domain”, but have no problem writing things like this:

for _ in 0 ..< n
{
    //
}

If you’re truly allergic to map{ _ in UIView() }, might I suggest the
following:

var array:[UIView] = []
    array.reserveCapacity(n)
for _ in 0 ..< n
{
    { array.append(UIView()) }()
}

That’s really all an array initializer that takes a block is really doing.
Or just use map.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to