[swift-evolution] [Pitch] New collection-based 'repeat' API

Xiaodi Wu xiaodi.wu at gmail.com
Tue May 2 00:02:48 CDT 2017


On Mon, May 1, 2017 at 9:34 PM, Karl Wagner via swift-evolution <
swift-evolution at swift.org> wrote:

> Currently, we have the Repeated<T> type, which presents a single element
> as though it were a Collection.
>
> > for i in repeatElement(1, count: 3) { print(i) }
> 1
> 1
> 1
>
> > for i in repeatElement([1, 2, 3], count: 3) { print(i) }
> [1, 2, 3]
> [1, 2, 3]
> [1, 2, 3]
>
>
> However, we lack the ability for Collections to repeat their contents in a
> single list; basically, some kind of “flatMap” to repeatElement’s “map”. So
> I’d like to pitch a new API for repeated values.
>
> - We would add a RepeatCollection<C: Collection> type, which loops over
> its base Collection a certain number of times (or until a maximum ‘count’).
>   Implementation might look something like this (https://gist.github.com/
> karwa/5228974a0b4dfd000a916f0aac2721c6), except that we’d add some
> optimised map(), filter() and contains() functions which apply the
> algorithm once to the base and multiply the result.
>
> - We would add 3 new functions to all Collections:
>
> /// Repeats the collection *itself* N times.
> ///
> func repeated(_ times: Int) -> RepeatCollection<CollectionOfOne<Self>>
>
> /// Repeats the collection’s *contents* N times.
> ///
> func repeatElements(_ times: Int) -> RepeatCollection<Self>
>
> /// Loops the collection’s contents to present a Collection of length N.
> ///
> func repeatElements(count: Int) -> RepeatCollection<Self>
>
>
> - We would replace the existing Repeated<T> type with a typealias to
> RepeatCollection<CollectionOfOne<T>>
> - The existing, top-level repeatElement(T, Int) function *could* stay,
> but could also be replaced with an incantation on CollectionOfOne. I’m
> fairly ambivalent about this point - it’d be nice to see the function go,
> but the replacement also isn’t obvious.
>
> Example usage of the new API:
>
> // Equivalent to repeatElement(1, count: 3)
>
> > for i in CollectionOfOne(1).repeatElements(3).forEach { print(i) }
> 1
> 1
> 1
>
> // Equivalent to repeatElement([1, 2, 3], count: 3)
>
> > for i in [1, 2, 3].repeated(3).forEach { print(i) }
> [1, 2, 3]
> [1, 2, 3]
> [1, 2, 3]
>
> // New, flat repetition
>
> > for i in [1, 2, 3].repeatElements(3) { print(i) }
> 1
> 2
> 3
> 1
> 2
> 3
> 1
> 2
> 3
>
> // New, flat repetition
>
> > for i in [1, 2, 3].repeatElements(count: 4) { print(i) }
> 1
> 2
> 3
> 1
>
> // Additional benefit: you can now repeat slices!
>
> > String(“yellow”.characters.dropFirst().dropLast().repeat(times: 3))
> “elloelloello"
>
>
> Thoughts?
>

OK, now as to your proposed APIs themselves, here are some critiques:

The issue you've identified with the cumbersome nature of CollectionOfOne
shows why repeatElement is currently a top-level function and intentionally
so. In brief, there's nothing special about Collection to make it the
obvious type on which to provide a `repeated` method. The _result_ of that
operation is a collection, but there's no reason the argument has to be.
The correct "type" on which to provide that method would be Any, IMO, but
of course we cannot provide extensions on Any. In general, in such
scenarios, the consistent design choice in the standard library is to
provide a free function.

Here, it is not inconsistent to _add_ something for repeating the elements
in a collection (to Collection itself) without also stuffing the existing
`repeatElement` functionality into Collection. TBH, the latter seems like
an orthogonal topic included for the express purpose of eliminating
top-level functions, without addressing the underlying reason for the
existence of these top-level functions in the first place (no extensions on
Any). So again, unrelated and worth setting aside, IMO.

Other minor points include that `repeatElements` doesn't meet standard API
naming guidelines. It should be `repeatingElements`. You also intuitively
tacked on a `times` argument label in the example usage even though your
proposed API doesn't have it. It suggests that `repeat[ing]Elements(3)` is
actually quite ambiguous: repeat the value 3, repeat the whole collection 3
times, or repeat so that the final count is 3? Better to have the label
always, I should think. Another point is that it'd take some justification
to include both flavors of `repeat[ing]Elements`, as repeating until a
final count is trivially composed with new one-sided ranges: `[1, 2,
3].repeatingElements(times: .max)[..<4]`.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170502/bddf158c/attachment.html>


More information about the swift-evolution mailing list