[Pitch] New collection-based 'repeat' API

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?

- Karl

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]`.

···

On Mon, May 1, 2017 at 9:34 PM, Karl Wagner via swift-evolution < swift-evolution@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?

Does this gain something by being part of the standard library as opposed
to being built on top of it?

···

On Mon, May 1, 2017 at 21:34 Karl Wagner via swift-evolution < swift-evolution@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?

- Karl

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

Well, somebody thought repeatElement<T> was general enough to make part of the standard library. If we’re going to allow repeating a single item as a Collection, we might as well allow generalise it to repeating any Collection in a loop (including a CollectionOfOne, which is the existing use-case).

Personally, I usually want to repeat a collection of things far more often than I want to repeat an individual thing. It annoys me that the standard library only provides the one I almost never need.

Additionally, it could help remove the top-level “repeatElement” function, which I know irritates some people who would rather us not have any top-level functions in the standard library.

- Karl

···

On 2 May 2017, at 04:44, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Does this gain something by being part of the standard library as opposed to being built on top of it?

I'm not giving my opinion, but quoting Ben Cohen's great list of questions to ask ourselves before adding something to the Standard Library:

All methods added to the standard library increase complexity, so need a strong justification to reduce the risk of API sprawl. When requesting additions/modifications, please keep the following questions in mind:

Is the suggested addition a common operation that many would find useful? Can it be flexible enough to cover different needs?
Will it encourage good practice? Might it be misused or encourage anti-patterns?
Can the operation be composed simply from existing std lib features? Is that composition intuitive/readable?
Is writing the equivalent by hand hard to get right? Are there common correctness traps that this addition would help avoid?
Is writing the equivalent by hand hard to make efficient? Are there common performance traps that this addition would help avoid?
Might a native implementation be able to execute more efficiently, by accessing internals, than the equivalent implementation using public APIs?

···

On 2 May 2017, at 07:02, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

On Mon, May 1, 2017 at 9:34 PM, Karl Wagner via swift-evolution <swift-evolution@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]`.

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

For reference, here are some links to previous discussions on related topics:

1) Kevin Ballard in December 2015: Proposal: CollectionType.cycle property for an infinite sequence <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151228/004635.html&gt;

2) Ben Cohen in February 2016: Sequence/Collection Enhancements <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170213/032120.html&gt; (one of the enhancements that Ben proposed to consider for adding to the standard library is a cycle method for Collection and/or Sequence. I don't think there is a more specific proposal for this yet, but at least we know it's on the core team's radar.

···

On 02.05.2017 04:34, Karl Wagner via swift-evolution 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

    > for i in repeatElement([1, 2, 3], count: 3) { print(i) }
    [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

    // Equivalent to repeatElement([1, 2, 3], count: 3)

    > for i in [1, 2, 3].repeated(3).forEach { print(i) }
    [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?

- Karl

>
> Does this gain something by being part of the standard library as
opposed to being built on top of it?

Well, somebody thought repeatElement<T> was general enough to make part of
the standard library. If we’re going to allow repeating a single item as a
Collection, we might as well allow generalise it to repeating any
Collection in a loop (including a CollectionOfOne, which is the existing
use-case).

That doesn't answer the question, though: does the feature you
propose--repeating any instance of Collection in a loop--gain anything by
being a part of the standard library rather than an extension to it?

There are _many_ useful algorithms that can be implemented on top of the
standard library and can be of general use; nonetheless, they aren't a part
of the standard library. IIUC, it's not because people just haven't had the
time to flesh it out; rather, it is a deliberate choice to have a small,
narrowly focused standard library. The philosophy, as I understand it, is
to make it convenient for users to roll their own conveniences rather than
providing all the bits and bobs in the library itself.

One of the points of differentiation between standard library and
Foundation is said to be whether something is necessary to support a core
language feature, in which case it goes into the standard library. As a
consequence, there are less commonly used parts of the standard library
which are there because they support other (decidedly not esoteric) parts
of the standard library and also happen to have some plausible public uses.
Taking a quick look into the repository, for instance, `repeatElement` is
used in the implementation of `UnicodeScalar`. However, just because
someone determined that `repeatElement` is worth making a public API (since
it's going to be in the standard library whether or not it's public),
doesn't _automatically_ mean that a generalization of it should be included
in the library as well.

Personally, I usually want to repeat a collection of things far more often

than I want to repeat an individual thing. It annoys me that the standard
library only provides the one I almost never need.

There are many facilities that the standard library does not provide. Heck,
we don't even have left padding for strings! (JavaScript reference, for
those following along.) Is there something about this particular feature
that makes its not being a part of the standard library uniquely
problematic?

Additionally, it could help remove the top-level “repeatElement” function,

which I know irritates some people who would rather us not have any
top-level functions in the standard library.

With source stability as a goal, the bar for removal isn't "irritates some
people." I actively use this function and there's no justification at all
for breaking it. Frankly, I cannot see removal of top-level functions
simply because they are top-level to be in scope essentially ever. So let's
subset that out of this discussion.

···

On Mon, May 1, 2017 at 9:52 PM, Karl Wagner <razielim@gmail.com> wrote:

> On 2 May 2017, at 04:44, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Xi: "Does this gain something by being part of the standard library?"
Me: "This gains discoverability and standardization by being part of the
standard library."
Xi: "By definition, if it's in the standard library, it becomes
standardized and discoverable."

We're in agreement, then?

No, you're missing the point entirely. Again, _anything_ gains
"discoverability and standardization" by being included as part of the
standard library. However, the standard library is deliberately small and
is intended to stay that way. So, what should be in and what should be out?
The question is: does this feature gain something by being part of the
standard library which other features that are deliberately excluded (like
left pad) do not?

Repeating a collection endlessly is a useful ability.

I don't doubt it. Is your argument that any useful and commonly used
feature should be part of the standard library? That's simply not the
stated criteria for inclusion in the standard library. Hence, why
Foundation exists outside of it. There's no point in debating these
criteria, as (afaict) that's not up for debate. Again, I don't make the
rules. I'm just saying they exist, and I'm arguing that we should abide by
them.

···

On Mon, May 1, 2017 at 11:22 PM, T.J. Usiyan <griotspeak@gmail.com> wrote:

Yes, it can be written on top of the standard library. It would be
generally nice not to require that *especially* when we can repeat single
elements without similar effort. The asymmetry is awkward to remember for
newbies and awkward to explain away with "we want a focused library so…
the Thing A stays but this logically related Thing B can't be in even
though showing you the ability to do A does tend to lead you to ask after
Thing B."

On Mon, May 1, 2017 at 11:55 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

That's a tautological argument, though. By definition, if it's in the
standard library, it becomes standardized and discoverable. This isn't at
all a limiting principle for what goes into the library and what doesn't.

And as I said, there are many commonly useful facilities that aren't part
of the standard library, by design and not by oversight. Left pad is one of
them.

I'm trying to tease out whether this particular proposal meets the
current bar for inclusion. If you believe left pad should be included, your
beef is with the deliberate choice to have a small standard library, which
as far as I know is not up for reconsideration.

On Mon, May 1, 2017 at 22:41 T.J. Usiyan <griotspeak@gmail.com> wrote:

This gains discoverability and standardization by being part of the
standard library. New folks would not have to import some library or roll
their own to get this reasonable to expect/hope or hope for functionality.
Perhaps removing the old function isn't going to work but repeating
collections is definitely something useful.

Left padding for strings would be nice as well, but that is neither here
nor there.

On Mon, May 1, 2017 at 11:29 PM, Xiaodi Wu via swift-evolution < >>> swift-evolution@swift.org> wrote:

On Mon, May 1, 2017 at 9:52 PM, Karl Wagner <razielim@gmail.com> wrote:

> On 2 May 2017, at 04:44, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
>
> Does this gain something by being part of the standard library as
opposed to being built on top of it?

Well, somebody thought repeatElement<T> was general enough to make
part of the standard library. If we’re going to allow repeating a single
item as a Collection, we might as well allow generalise it to repeating any
Collection in a loop (including a CollectionOfOne, which is the existing
use-case).

That doesn't answer the question, though: does the feature you
propose--repeating any instance of Collection in a loop--gain anything by
being a part of the standard library rather than an extension to it?

There are _many_ useful algorithms that can be implemented on top of
the standard library and can be of general use; nonetheless, they aren't a
part of the standard library. IIUC, it's not because people just haven't
had the time to flesh it out; rather, it is a deliberate choice to have a
small, narrowly focused standard library. The philosophy, as I understand
it, is to make it convenient for users to roll their own conveniences
rather than providing all the bits and bobs in the library itself.

One of the points of differentiation between standard library and
Foundation is said to be whether something is necessary to support a core
language feature, in which case it goes into the standard library. As a
consequence, there are less commonly used parts of the standard library
which are there because they support other (decidedly not esoteric) parts
of the standard library and also happen to have some plausible public uses.
Taking a quick look into the repository, for instance, `repeatElement` is
used in the implementation of `UnicodeScalar`. However, just because
someone determined that `repeatElement` is worth making a public API (since
it's going to be in the standard library whether or not it's public),
doesn't _automatically_ mean that a generalization of it should be included
in the library as well.

Personally, I usually want to repeat a collection of things far more

often than I want to repeat an individual thing. It annoys me that the
standard library only provides the one I almost never need.

There are many facilities that the standard library does not provide.
Heck, we don't even have left padding for strings! (JavaScript reference,
for those following along.) Is there something about this particular
feature that makes its not being a part of the standard library uniquely
problematic?

Additionally, it could help remove the top-level “repeatElement”

function, which I know irritates some people who would rather us not have
any top-level functions in the standard library.

With source stability as a goal, the bar for removal isn't "irritates
some people." I actively use this function and there's no justification at
all for breaking it. Frankly, I cannot see removal of top-level functions
simply because they are top-level to be in scope essentially ever. So let's
subset that out of this discussion.

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

This gains discoverability and standardization by being part of the
standard library. New folks would not have to import some library or roll
their own to get this reasonable to expect/hope or hope for functionality.
Perhaps removing the old function isn't going to work but repeating
collections is definitely something useful.

Left padding for strings would be nice as well, but that is neither here
nor there.

···

On Mon, May 1, 2017 at 11:29 PM, Xiaodi Wu via swift-evolution < swift-evolution@swift.org> wrote:

On Mon, May 1, 2017 at 9:52 PM, Karl Wagner <razielim@gmail.com> wrote:

> On 2 May 2017, at 04:44, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
>
> Does this gain something by being part of the standard library as
opposed to being built on top of it?

Well, somebody thought repeatElement<T> was general enough to make part
of the standard library. If we’re going to allow repeating a single item as
a Collection, we might as well allow generalise it to repeating any
Collection in a loop (including a CollectionOfOne, which is the existing
use-case).

That doesn't answer the question, though: does the feature you
propose--repeating any instance of Collection in a loop--gain anything by
being a part of the standard library rather than an extension to it?

There are _many_ useful algorithms that can be implemented on top of the
standard library and can be of general use; nonetheless, they aren't a part
of the standard library. IIUC, it's not because people just haven't had the
time to flesh it out; rather, it is a deliberate choice to have a small,
narrowly focused standard library. The philosophy, as I understand it, is
to make it convenient for users to roll their own conveniences rather than
providing all the bits and bobs in the library itself.

One of the points of differentiation between standard library and
Foundation is said to be whether something is necessary to support a core
language feature, in which case it goes into the standard library. As a
consequence, there are less commonly used parts of the standard library
which are there because they support other (decidedly not esoteric) parts
of the standard library and also happen to have some plausible public uses.
Taking a quick look into the repository, for instance, `repeatElement` is
used in the implementation of `UnicodeScalar`. However, just because
someone determined that `repeatElement` is worth making a public API (since
it's going to be in the standard library whether or not it's public),
doesn't _automatically_ mean that a generalization of it should be included
in the library as well.

Personally, I usually want to repeat a collection of things far more often

than I want to repeat an individual thing. It annoys me that the standard
library only provides the one I almost never need.

There are many facilities that the standard library does not provide.
Heck, we don't even have left padding for strings! (JavaScript reference,
for those following along.) Is there something about this particular
feature that makes its not being a part of the standard library uniquely
problematic?

Additionally, it could help remove the top-level “repeatElement” function,

which I know irritates some people who would rather us not have any
top-level functions in the standard library.

With source stability as a goal, the bar for removal isn't "irritates some
people." I actively use this function and there's no justification at all
for breaking it. Frankly, I cannot see removal of top-level functions
simply because they are top-level to be in scope essentially ever. So let's
subset that out of this discussion.

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

Xi: "Does this gain something by being part of the standard library?"
Me: "This gains discoverability and standardization by being part of the
standard library."
Xi: "By definition, if it's in the standard library, it becomes
standardized and discoverable."

We're in agreement, then?

Repeating a collection endlessly is a useful ability. Yes, it can be
written on top of the standard library. It would be generally nice not to
require that *especially* when we can repeat single elements without
similar effort. The asymmetry is awkward to remember for newbies and
awkward to explain away with "we want a focused library so… the Thing A
stays but this logically related Thing B can't be in even though showing
you the ability to do A does tend to lead you to ask after Thing B."

···

On Mon, May 1, 2017 at 11:55 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

That's a tautological argument, though. By definition, if it's in the
standard library, it becomes standardized and discoverable. This isn't at
all a limiting principle for what goes into the library and what doesn't.

And as I said, there are many commonly useful facilities that aren't part
of the standard library, by design and not by oversight. Left pad is one of
them.

I'm trying to tease out whether this particular proposal meets the current
bar for inclusion. If you believe left pad should be included, your beef is
with the deliberate choice to have a small standard library, which as far
as I know is not up for reconsideration.

On Mon, May 1, 2017 at 22:41 T.J. Usiyan <griotspeak@gmail.com> wrote:

This gains discoverability and standardization by being part of the
standard library. New folks would not have to import some library or roll
their own to get this reasonable to expect/hope or hope for functionality.
Perhaps removing the old function isn't going to work but repeating
collections is definitely something useful.

Left padding for strings would be nice as well, but that is neither here
nor there.

On Mon, May 1, 2017 at 11:29 PM, Xiaodi Wu via swift-evolution < >> swift-evolution@swift.org> wrote:

On Mon, May 1, 2017 at 9:52 PM, Karl Wagner <razielim@gmail.com> wrote:

> On 2 May 2017, at 04:44, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
>
> Does this gain something by being part of the standard library as
opposed to being built on top of it?

Well, somebody thought repeatElement<T> was general enough to make part
of the standard library. If we’re going to allow repeating a single item as
a Collection, we might as well allow generalise it to repeating any
Collection in a loop (including a CollectionOfOne, which is the existing
use-case).

That doesn't answer the question, though: does the feature you
propose--repeating any instance of Collection in a loop--gain anything by
being a part of the standard library rather than an extension to it?

There are _many_ useful algorithms that can be implemented on top of the
standard library and can be of general use; nonetheless, they aren't a part
of the standard library. IIUC, it's not because people just haven't had the
time to flesh it out; rather, it is a deliberate choice to have a small,
narrowly focused standard library. The philosophy, as I understand it, is
to make it convenient for users to roll their own conveniences rather than
providing all the bits and bobs in the library itself.

One of the points of differentiation between standard library and
Foundation is said to be whether something is necessary to support a core
language feature, in which case it goes into the standard library. As a
consequence, there are less commonly used parts of the standard library
which are there because they support other (decidedly not esoteric) parts
of the standard library and also happen to have some plausible public uses.
Taking a quick look into the repository, for instance, `repeatElement` is
used in the implementation of `UnicodeScalar`. However, just because
someone determined that `repeatElement` is worth making a public API (since
it's going to be in the standard library whether or not it's public),
doesn't _automatically_ mean that a generalization of it should be included
in the library as well.

Personally, I usually want to repeat a collection of things far more

often than I want to repeat an individual thing. It annoys me that the
standard library only provides the one I almost never need.

There are many facilities that the standard library does not provide.
Heck, we don't even have left padding for strings! (JavaScript reference,
for those following along.) Is there something about this particular
feature that makes its not being a part of the standard library uniquely
problematic?

Additionally, it could help remove the top-level “repeatElement”

function, which I know irritates some people who would rather us not have
any top-level functions in the standard library.

With source stability as a goal, the bar for removal isn't "irritates
some people." I actively use this function and there's no justification at
all for breaking it. Frankly, I cannot see removal of top-level functions
simply because they are top-level to be in scope essentially ever. So let's
subset that out of this discussion.

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

That's a tautological argument, though. By definition, if it's in the
standard library, it becomes standardized and discoverable. This isn't at
all a limiting principle for what goes into the library and what doesn't.

And as I said, there are many commonly useful facilities that aren't part
of the standard library, by design and not by oversight. Left pad is one of
them.

I'm trying to tease out whether this particular proposal meets the current
bar for inclusion. If you believe left pad should be included, your beef is
with the deliberate choice to have a small standard library, which as far
as I know is not up for reconsideration.

···

On Mon, May 1, 2017 at 22:41 T.J. Usiyan <griotspeak@gmail.com> wrote:

This gains discoverability and standardization by being part of the
standard library. New folks would not have to import some library or roll
their own to get this reasonable to expect/hope or hope for functionality.
Perhaps removing the old function isn't going to work but repeating
collections is definitely something useful.

Left padding for strings would be nice as well, but that is neither here
nor there.

On Mon, May 1, 2017 at 11:29 PM, Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote:

On Mon, May 1, 2017 at 9:52 PM, Karl Wagner <razielim@gmail.com> wrote:

> On 2 May 2017, at 04:44, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
>
> Does this gain something by being part of the standard library as
opposed to being built on top of it?

Well, somebody thought repeatElement<T> was general enough to make part
of the standard library. If we’re going to allow repeating a single item as
a Collection, we might as well allow generalise it to repeating any
Collection in a loop (including a CollectionOfOne, which is the existing
use-case).

That doesn't answer the question, though: does the feature you
propose--repeating any instance of Collection in a loop--gain anything by
being a part of the standard library rather than an extension to it?

There are _many_ useful algorithms that can be implemented on top of the
standard library and can be of general use; nonetheless, they aren't a part
of the standard library. IIUC, it's not because people just haven't had the
time to flesh it out; rather, it is a deliberate choice to have a small,
narrowly focused standard library. The philosophy, as I understand it, is
to make it convenient for users to roll their own conveniences rather than
providing all the bits and bobs in the library itself.

One of the points of differentiation between standard library and
Foundation is said to be whether something is necessary to support a core
language feature, in which case it goes into the standard library. As a
consequence, there are less commonly used parts of the standard library
which are there because they support other (decidedly not esoteric) parts
of the standard library and also happen to have some plausible public uses.
Taking a quick look into the repository, for instance, `repeatElement` is
used in the implementation of `UnicodeScalar`. However, just because
someone determined that `repeatElement` is worth making a public API (since
it's going to be in the standard library whether or not it's public),
doesn't _automatically_ mean that a generalization of it should be included
in the library as well.

Personally, I usually want to repeat a collection of things far more

often than I want to repeat an individual thing. It annoys me that the
standard library only provides the one I almost never need.

There are many facilities that the standard library does not provide.
Heck, we don't even have left padding for strings! (JavaScript reference,
for those following along.) Is there something about this particular
feature that makes its not being a part of the standard library uniquely
problematic?

Additionally, it could help remove the top-level “repeatElement”

function, which I know irritates some people who would rather us not have
any top-level functions in the standard library.

With source stability as a goal, the bar for removal isn't "irritates
some people." I actively use this function and there's no justification at
all for breaking it. Frankly, I cannot see removal of top-level functions
simply because they are top-level to be in scope essentially ever. So let's
subset that out of this discussion.

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

>
> Does this gain something by being part of the standard library as opposed to being built on top of it?

Well, somebody thought repeatElement<T> was general enough to make part of the standard library. If we’re going to allow repeating a single item as a Collection, we might as well allow generalise it to repeating any Collection in a loop (including a CollectionOfOne, which is the existing use-case).

That doesn't answer the question, though: does the feature you propose--repeating any instance of Collection in a loop--gain anything by being a part of the standard library rather than an extension to it?

There are _many_ useful algorithms that can be implemented on top of the standard library and can be of general use; nonetheless, they aren't a part of the standard library. IIUC, it's not because people just haven't had the time to flesh it out; rather, it is a deliberate choice to have a small, narrowly focused standard library. The philosophy, as I understand it, is to make it convenient for users to roll their own conveniences rather than providing all the bits and bobs in the library itself.

One of the points of differentiation between standard library and Foundation is said to be whether something is necessary to support a core language feature, in which case it goes into the standard library. As a consequence, there are less commonly used parts of the standard library which are there because they support other (decidedly not esoteric) parts of the standard library and also happen to have some plausible public uses. Taking a quick look into the repository, for instance, `repeatElement` is used in the implementation of `UnicodeScalar`. However, just because someone determined that `repeatElement` is worth making a public API (since it's going to be in the standard library whether or not it's public), doesn't _automatically_ mean that a generalization of it should be included in the library as well.

This seems contradictory. Either the standard library is small and deliberately focussed; or it isn’t and it’s okay for random "bits and bobs” such as repeatElement to be public just because the standard library arbitrarily uses them somewhere.

Either “repeat” functionality (in general) is useful and the generalised behaviour should be in the standard library, or none of it should be.

Personally, I usually want to repeat a collection of things far more often than I want to repeat an individual thing. It annoys me that the standard library only provides the one I almost never need.

There are many facilities that the standard library does not provide. Heck, we don't even have left padding for strings! (JavaScript reference, for those following along.) Is there something about this particular feature that makes its not being a part of the standard library uniquely problematic?

Additionally, it could help remove the top-level “repeatElement” function, which I know irritates some people who would rather us not have any top-level functions in the standard library.

With source stability as a goal, the bar for removal isn't "irritates some people." I actively use this function and there's no justification at all for breaking it.
Frankly, I cannot see removal of top-level functions simply because they are top-level to be in scope essentially ever. So let's subset that out of this discussion.

Again, this seems contradictory given your comments just a few lines up about how spartan the stdlib is supposed to be. Why do you insist that this single-purpose function remain, and the more broadly-useful, generalised functionality cannot possibly be a fit for the standard library? It seems that the reverse is more likely to be true.

As I said, I personally don’t care about what happens to the top-level function. This is only a pitch, so I wanted to hear from those people who really do want to remove them all before writing up a full proposal.

- Karl

···

On 2 May 2017, at 05:29, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
On Mon, May 1, 2017 at 9:52 PM, Karl Wagner <razielim@gmail.com <mailto:razielim@gmail.com>> wrote:
> On 2 May 2017, at 04:44, Xiaodi Wu <xiaodi.wu@gmail.com <mailto:xiaodi.wu@gmail.com>> wrote:

I'm not giving my opinion, but quoting Ben Cohen's great list of questions
to ask ourselves before adding something to the Standard Library:

All methods added to the standard library increase complexity, so need a
strong justification to reduce the risk of API sprawl. When requesting
additions/modifications, please keep the following questions in mind:

   1. Is the suggested addition a common operation that many would find
   useful? Can it be flexible enough to cover different needs?
   2. Will it encourage good practice? Might it be misused or encourage
   anti-patterns?
   3. Can the operation be composed simply from existing std lib
   features? Is that composition intuitive/readable?
   4. Is writing the equivalent by hand hard to get right? Are there
   common correctness traps that this addition would help avoid?
   5. Is writing the equivalent by hand hard to make efficient? Are there
   common performance traps that this addition would help avoid?

I would advocate that point 5 can indeed be a bit hard (however I am not

sure that would justify the addition to the standard library). I often use
the functions "repmat" and "ndgrid" in MATLAB to prepare collections of
indexes to consider batch computations / combinatory problems. Due to the
limitation of the MATLAB language only indexes or parameters values are
usually contained in the repeated collections/matrices. As a consequence,
the object obtained through the repeatition usually remain manageable in
terms of memory.

If, however, people would like to do such things directly on some
collections of objects with resaonnable size, we might end up copying a lot
of data for nothing. It might also force programmers to modify their
classes / data structure to avoid this problem. As long as the "repeated"
data/collection is only used only for read operations (which I imagine to
be one of the main use cases with the for-in loops), copies could be
prevented.

···

On Tue, May 2, 2017 at 8:50 AM, David Hart via swift-evolution < swift-evolution@swift.org> wrote:

   1. Might a native implementation be able to execute more efficiently,
   by accessing internals, than the equivalent implementation using public
   APIs?

On 2 May 2017, at 07:02, Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote:

On Mon, May 1, 2017 at 9:34 PM, Karl Wagner via swift-evolution < > swift-evolution@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]`.

_______________________________________________
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

Xi: "Does this gain something by being part of the standard library?"
Me: "This gains discoverability and standardization by being part of the standard library."
Xi: "By definition, if it's in the standard library, it becomes standardized and discoverable."

We're in agreement, then?

No, you're missing the point entirely. Again, _anything_ gains "discoverability and standardization" by being included as part of the standard library. However, the standard library is deliberately small and is intended to stay that way. So, what should be in and what should be out? The question is: does this feature gain something by being part of the standard library which other features that are deliberately excluded (like left pad) do not?

I’m going to back Xiaodi on this one. The standard library is the standard for the language, by definition. That comes with some great things, and some concerning things.

If we decided anything that was generic and useful as a basis for programming got in, we wouldn’t call it the “Standard Library” - it would be the Kitchen Sink Library. It would be huge. The bar has to be set higher for the library.

Why is the current repeat functionality in there? Because Strings use it. Why is it public? Because, like you, people noticed it and said “That’s great generic functionality, why not expose it, and let everyone use it?” But that isn’t the bar for adding things: the bar is far higher for them to be added. Especially now as we’re trying to mature Swift from it’s immature fast-moving state. This may be the bar for *exposing* generic things, but the higher bar of “is this core?” may not be met with this proposal.

Don’t get me wrong, I think it’s a great idea. I just am not sure it meets the bar of “core”.

···

On 2 May 2017, at 2:33 pm, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:
On Mon, May 1, 2017 at 11:22 PM, T.J. Usiyan <griotspeak@gmail.com <mailto:griotspeak@gmail.com>> wrote:

Repeating a collection endlessly is a useful ability.

I don't doubt it. Is your argument that any useful and commonly used feature should be part of the standard library? That's simply not the stated criteria for inclusion in the standard library. Hence, why Foundation exists outside of it. There's no point in debating these criteria, as (afaict) that's not up for debate. Again, I don't make the rules. I'm just saying they exist, and I'm arguing that we should abide by them.

Yes, it can be written on top of the standard library. It would be generally nice not to require that *especially* when we can repeat single elements without similar effort. The asymmetry is awkward to remember for newbies and awkward to explain away with "we want a focused library so… the Thing A stays but this logically related Thing B can't be in even though showing you the ability to do A does tend to lead you to ask after Thing B."

On Mon, May 1, 2017 at 11:55 PM, Xiaodi Wu <xiaodi.wu@gmail.com <mailto:xiaodi.wu@gmail.com>> wrote:
That's a tautological argument, though. By definition, if it's in the standard library, it becomes standardized and discoverable. This isn't at all a limiting principle for what goes into the library and what doesn't.

And as I said, there are many commonly useful facilities that aren't part of the standard library, by design and not by oversight. Left pad is one of them.

I'm trying to tease out whether this particular proposal meets the current bar for inclusion. If you believe left pad should be included, your beef is with the deliberate choice to have a small standard library, which as far as I know is not up for reconsideration.

On Mon, May 1, 2017 at 22:41 T.J. Usiyan <griotspeak@gmail.com <mailto:griotspeak@gmail.com>> wrote:
This gains discoverability and standardization by being part of the standard library. New folks would not have to import some library or roll their own to get this reasonable to expect/hope or hope for functionality. Perhaps removing the old function isn't going to work but repeating collections is definitely something useful.

Left padding for strings would be nice as well, but that is neither here nor there.

On Mon, May 1, 2017 at 11:29 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Mon, May 1, 2017 at 9:52 PM, Karl Wagner <razielim@gmail.com <mailto:razielim@gmail.com>> wrote:

> On 2 May 2017, at 04:44, Xiaodi Wu <xiaodi.wu@gmail.com <mailto:xiaodi.wu@gmail.com>> wrote:
>
> Does this gain something by being part of the standard library as opposed to being built on top of it?

Well, somebody thought repeatElement<T> was general enough to make part of the standard library. If we’re going to allow repeating a single item as a Collection, we might as well allow generalise it to repeating any Collection in a loop (including a CollectionOfOne, which is the existing use-case).

That doesn't answer the question, though: does the feature you propose--repeating any instance of Collection in a loop--gain anything by being a part of the standard library rather than an extension to it?

There are _many_ useful algorithms that can be implemented on top of the standard library and can be of general use; nonetheless, they aren't a part of the standard library. IIUC, it's not because people just haven't had the time to flesh it out; rather, it is a deliberate choice to have a small, narrowly focused standard library. The philosophy, as I understand it, is to make it convenient for users to roll their own conveniences rather than providing all the bits and bobs in the library itself.

One of the points of differentiation between standard library and Foundation is said to be whether something is necessary to support a core language feature, in which case it goes into the standard library. As a consequence, there are less commonly used parts of the standard library which are there because they support other (decidedly not esoteric) parts of the standard library and also happen to have some plausible public uses. Taking a quick look into the repository, for instance, `repeatElement` is used in the implementation of `UnicodeScalar`. However, just because someone determined that `repeatElement` is worth making a public API (since it's going to be in the standard library whether or not it's public), doesn't _automatically_ mean that a generalization of it should be included in the library as well.

Personally, I usually want to repeat a collection of things far more often than I want to repeat an individual thing. It annoys me that the standard library only provides the one I almost never need.

There are many facilities that the standard library does not provide. Heck, we don't even have left padding for strings! (JavaScript reference, for those following along.) Is there something about this particular feature that makes its not being a part of the standard library uniquely problematic?

Additionally, it could help remove the top-level “repeatElement” function, which I know irritates some people who would rather us not have any top-level functions in the standard library.

With source stability as a goal, the bar for removal isn't "irritates some people." I actively use this function and there's no justification at all for breaking it. Frankly, I cannot see removal of top-level functions simply because they are top-level to be in scope essentially ever. So let's subset that out of this discussion.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

This should be *February 2017*, of course. Sorry.

···

On 02.05.2017 18:33, Ole Begemann via swift-evolution wrote:

For reference, here are some links to previous discussions on related topics:

1) Kevin Ballard in December 2015: Proposal: CollectionType.cycle property for an infinite sequence <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151228/004635.html&gt;

2) Ben Cohen in February 2016: Sequence/Collection Enhancements <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170213/032120.html&gt; (one of the enhancements that Ben proposed to consider for adding to the standard library is a cycle method for Collection and/or Sequence. I don't think there is a more specific proposal for this yet, but at least we know it's on the core team's radar.

For what it's worth, a good Swift implementation of left-padding would probably *use* `repeatElement`:

  extension String {
    mutating func leftPad(to intendedCount: Int, with char: Character = " ") {
      let extraCount = max(intendedCount - count, 0)
      let extras = repeatElement(char, count: extraCount)
      insert(contentsOf: extras, at: startIndex)
    }
  }

And, for that matter, `repeatElement` could be used to implement "repeat this collection":

  repeatElement(c, count: n).joined()

So I agree with you, Xiaodi, that there's no rush to do this. If we change our minds later, we can always turn `Repeated<T>` into a generic typealias for `RepeatedCollection<CollectionOfOne<T>>`.

···

On May 1, 2017, at 8:29 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

Heck, we don't even have left padding for strings!

--
Brent Royal-Gordon
Architechies

>
> Does this gain something by being part of the standard library as
opposed to being built on top of it?

Well, somebody thought repeatElement<T> was general enough to make part
of the standard library. If we’re going to allow repeating a single item as
a Collection, we might as well allow generalise it to repeating any
Collection in a loop (including a CollectionOfOne, which is the existing
use-case).

That doesn't answer the question, though: does the feature you
propose--repeating any instance of Collection in a loop--gain anything by
being a part of the standard library rather than an extension to it?

There are _many_ useful algorithms that can be implemented on top of the
standard library and can be of general use; nonetheless, they aren't a part
of the standard library. IIUC, it's not because people just haven't had the
time to flesh it out; rather, it is a deliberate choice to have a small,
narrowly focused standard library. The philosophy, as I understand it, is
to make it convenient for users to roll their own conveniences rather than
providing all the bits and bobs in the library itself.

One of the points of differentiation between standard library and
Foundation is said to be whether something is necessary to support a core
language feature, in which case it goes into the standard library. As a
consequence, there are less commonly used parts of the standard library
which are there because they support other (decidedly not esoteric) parts
of the standard library and also happen to have some plausible public uses.
Taking a quick look into the repository, for instance, `repeatElement` is
used in the implementation of `UnicodeScalar`. However, just because
someone determined that `repeatElement` is worth making a public API (since
it's going to be in the standard library whether or not it's public),
doesn't _automatically_ mean that a generalization of it should be included
in the library as well.

This seems contradictory. Either the standard library is small and
deliberately focussed; or it isn’t and it’s okay for random "bits and bobs”
such as repeatElement to be public just because the standard library
arbitrarily uses them somewhere.

I don't see how. The standard library _is_ small--and it's focused, though
not perhaps on what you think it should be. It's not that only the most
commonly sought-after features go into the standard library; it's that only
such features as are necessary to support the core language go into the
standard library. `repeatElement` isn't randomly part of the library; it's
used to implement strings.

Either “repeat” functionality (in general) is useful and the generalised

behaviour should be in the standard library, or none of it should be.

That doesn't follow at all. It's like saying, either types (in general) are
useful and higher-kinded types should be supported by Swift, or Swift
should be untyped.

Personally, I usually want to repeat a collection of things far more often

than I want to repeat an individual thing. It annoys me that the standard
library only provides the one I almost never need.

There are many facilities that the standard library does not provide.
Heck, we don't even have left padding for strings! (JavaScript reference,
for those following along.) Is there something about this particular
feature that makes its not being a part of the standard library uniquely
problematic?

Additionally, it could help remove the top-level “repeatElement” function,

which I know irritates some people who would rather us not have any
top-level functions in the standard library.

With source stability as a goal, the bar for removal isn't "irritates some
people." I actively use this function and there's no justification at all
for breaking it.

Frankly, I cannot see removal of top-level functions simply because they
are top-level to be in scope essentially ever. So let's subset that out of
this discussion.

Again, this seems contradictory given your comments just a few lines up
about how spartan the stdlib is supposed to be. Why do you insist that this
single-purpose function remain,

*I'm* not inventing the source stability criteria here. It's been made very
clear that the bar for removing something existing the language now is very
high and not at all based on whether it would be included in the first
place if it were proposed today. There have been several criteria laid out
for such source-breaking changes, and "irritates some people" doesn't meet
that bar. In insisting on preserving source stability, I'm only insisting
that we respect the process laid out for Swift evolution, because that's
the only way this thing can work. Again, I don't come up with the criteria,
but we shouldn't need to litigate the ground rules every time an idea is
discussed.

and the more broadly-useful, generalised functionality cannot possibly be
a fit for the standard library?

I think, if you read back, I have never insisted that your proposed
functionality is not a fit. I simply asked you a question: does this
generalized feature fit the existing, stated focus that the standard
library doesn't vend every useful function, but only those necessary for
supporting the core language? It appears that _you're_ saying it doesn't,
but that you also don't agree with those criteria. Again, I don't come up
with the criteria. I'm just bringing up that they exist.

···

On Mon, May 1, 2017 at 10:52 PM, Karl Wagner <razielim@gmail.com> wrote:

On 2 May 2017, at 05:29, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
On Mon, May 1, 2017 at 9:52 PM, Karl Wagner <razielim@gmail.com> wrote:

> On 2 May 2017, at 04:44, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

It seems that the reverse is more likely to be true.

As I said, I personally don’t care about what happens to the top-level
function. This is only a pitch, so I wanted to hear from those people who
really do want to remove them all before writing up a full proposal.

>
> Does this gain something by being part of the standard library as
opposed to being built on top of it?

Well, somebody thought repeatElement<T> was general enough to make part
of the standard library. If we’re going to allow repeating a single item as
a Collection, we might as well allow generalise it to repeating any
Collection in a loop (including a CollectionOfOne, which is the existing
use-case).

That doesn't answer the question, though: does the feature you
propose--repeating any instance of Collection in a loop--gain anything by
being a part of the standard library rather than an extension to it?

There are _many_ useful algorithms that can be implemented on top of the
standard library and can be of general use; nonetheless, they aren't a part
of the standard library. IIUC, it's not because people just haven't had the
time to flesh it out; rather, it is a deliberate choice to have a small,
narrowly focused standard library. The philosophy, as I understand it, is
to make it convenient for users to roll their own conveniences rather than
providing all the bits and bobs in the library itself.

One of the points of differentiation between standard library and
Foundation is said to be whether something is necessary to support a core
language feature, in which case it goes into the standard library. As a
consequence, there are less commonly used parts of the standard library
which are there because they support other (decidedly not esoteric) parts
of the standard library and also happen to have some plausible public uses.
Taking a quick look into the repository, for instance, `repeatElement` is
used in the implementation of `UnicodeScalar`. However, just because
someone determined that `repeatElement` is worth making a public API (since
it's going to be in the standard library whether or not it's public),
doesn't _automatically_ mean that a generalization of it should be included
in the library as well.

This seems contradictory. Either the standard library is small and
deliberately focussed; or it isn’t and it’s okay for random "bits and bobs”
such as repeatElement to be public just because the standard library
arbitrarily uses them somewhere.

I don't see how. The standard library _is_ small--and it's focused, though
not perhaps on what you think it should be. It's not that only the most
commonly sought-after features go into the standard library; it's that only
such features as are necessary to support the core language go into the
standard library. `repeatElement` isn't randomly part of the library; it's
used to implement strings.

Either “repeat” functionality (in general) is useful and the generalised

behaviour should be in the standard library, or none of it should be.

That doesn't follow at all. It's like saying, either types (in general)
are useful and higher-kinded types should be supported by Swift, or Swift
should be untyped.

Personally, I usually want to repeat a collection of things far more

often than I want to repeat an individual thing. It annoys me that the
standard library only provides the one I almost never need.

There are many facilities that the standard library does not provide.
Heck, we don't even have left padding for strings! (JavaScript reference,
for those following along.) Is there something about this particular
feature that makes its not being a part of the standard library uniquely
problematic?

Additionally, it could help remove the top-level “repeatElement”

function, which I know irritates some people who would rather us not have
any top-level functions in the standard library.

With source stability as a goal, the bar for removal isn't "irritates
some people." I actively use this function and there's no justification at
all for breaking it.

Frankly, I cannot see removal of top-level functions simply because they
are top-level to be in scope essentially ever. So let's subset that out of
this discussion.

Again, this seems contradictory given your comments just a few lines up
about how spartan the stdlib is supposed to be. Why do you insist that this
single-purpose function remain,

*I'm* not inventing the source stability criteria here. It's been made
very clear that the bar for removing something existing the language now is
very high and not at all based on whether it would be included in the first
place if it were proposed today. There have been several criteria laid out
for such source-breaking changes, and "irritates some people" doesn't meet
that bar. In insisting on preserving source stability, I'm only insisting
that we respect the process laid out for Swift evolution, because that's
the only way this thing can work. Again, I don't come up with the criteria,
but we shouldn't need to litigate the ground rules every time an idea is
discussed.

I should add, I have always personally been sympathetic towards the idea
that free functions are less discoverable than methods, and that the
standard library is better off with fewer of them. Back in the Swift 3
days, I was definitely in support of removing a number of these, such as
`max` and `min`. I believe you and I were part of such a conversation back
then. But I think it's important to play by the rules, so to speak, and
source stability is here and clearly being prioritized. I believe very
strongly that this process only works when we respect and work together to
promote the identified priorities, not poke holes against them.

···

On Mon, May 1, 2017 at 11:15 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Mon, May 1, 2017 at 10:52 PM, Karl Wagner <razielim@gmail.com> wrote:

On 2 May 2017, at 05:29, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
On Mon, May 1, 2017 at 9:52 PM, Karl Wagner <razielim@gmail.com> wrote:

> On 2 May 2017, at 04:44, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

and the more broadly-useful, generalised functionality cannot possibly be
a fit for the standard library?

I think, if you read back, I have never insisted that your proposed
functionality is not a fit. I simply asked you a question: does this
generalized feature fit the existing, stated focus that the standard
library doesn't vend every useful function, but only those necessary for
supporting the core language? It appears that _you're_ saying it doesn't,
but that you also don't agree with those criteria. Again, I don't come up
with the criteria. I'm just bringing up that they exist.

It seems that the reverse is more likely to be true.

As I said, I personally don’t care about what happens to the top-level
function. This is only a pitch, so I wanted to hear from those people who
really do want to remove them all before writing up a full proposal.

Xi: "Does this gain something by being part of the standard library?"
Me: "This gains discoverability and standardization by being part of the
standard library."
Xi: "By definition, if it's in the standard library, it becomes
standardized and discoverable."

We're in agreement, then?

No, you're missing the point entirely. Again, _anything_ gains
"discoverability and standardization" by being included as part of the
standard library. However, the standard library is deliberately small and
is intended to stay that way. So, what should be in and what should be out?
The question is: does this feature gain something by being part of the
standard library which other features that are deliberately excluded (like
left pad) do not?

I’m going to back Xiaodi on this one. The standard library is the standard
for the language, by definition. That comes with some great things, and
some concerning things.

If we decided anything that was generic and useful as a basis for
programming got in, we wouldn’t call it the “Standard Library” - it would
be the Kitchen Sink Library. It would be huge. The bar has to be set higher
for the library.

Why is the current repeat functionality in there? Because Strings use it.
Why is it public? Because, like you, people noticed it and said “That’s
great generic functionality, why not expose it, and let everyone use it?”
But that isn’t the bar for adding things: the bar is far higher for them to
be added. Especially now as we’re trying to mature Swift from it’s immature
fast-moving state. This may be the bar for *exposing* generic things, but
the higher bar of “is this core?” may not be met with this proposal.

Don’t get me wrong, I think it’s a great idea. I just am not sure it meets
the bar of “core”.

Heck, it may even meet the bar for "core"! But not even core things all go
into the standard library (for example, all of Foundation and Dispatch).

For instance, many people ask for additional math functionality here, and
the repeated statement from the core team is that they'd like to see it as
a third-party library, gain traction, then get nominated for inclusion as a
core library. But even then, notice: core, not standard.

···

On Mon, May 1, 2017 at 11:47 PM, Rod Brown <rodney.brown6@icloud.com> wrote:

On 2 May 2017, at 2:33 pm, Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote:
On Mon, May 1, 2017 at 11:22 PM, T.J. Usiyan <griotspeak@gmail.com> wrote:

Repeating a collection endlessly is a useful ability.

I don't doubt it. Is your argument that any useful and commonly used
feature should be part of the standard library? That's simply not the
stated criteria for inclusion in the standard library. Hence, why
Foundation exists outside of it. There's no point in debating these
criteria, as (afaict) that's not up for debate. Again, I don't make the
rules. I'm just saying they exist, and I'm arguing that we should abide by
them.

Yes, it can be written on top of the standard library. It would be
generally nice not to require that *especially* when we can repeat single
elements without similar effort. The asymmetry is awkward to remember for
newbies and awkward to explain away with "we want a focused library so…
the Thing A stays but this logically related Thing B can't be in even
though showing you the ability to do A does tend to lead you to ask after
Thing B."

On Mon, May 1, 2017 at 11:55 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

That's a tautological argument, though. By definition, if it's in the
standard library, it becomes standardized and discoverable. This isn't at
all a limiting principle for what goes into the library and what doesn't.

And as I said, there are many commonly useful facilities that aren't
part of the standard library, by design and not by oversight. Left pad is
one of them.

I'm trying to tease out whether this particular proposal meets the
current bar for inclusion. If you believe left pad should be included, your
beef is with the deliberate choice to have a small standard library, which
as far as I know is not up for reconsideration.

On Mon, May 1, 2017 at 22:41 T.J. Usiyan <griotspeak@gmail.com> wrote:

This gains discoverability and standardization by being part of the
standard library. New folks would not have to import some library or roll
their own to get this reasonable to expect/hope or hope for functionality.
Perhaps removing the old function isn't going to work but repeating
collections is definitely something useful.

Left padding for strings would be nice as well, but that is neither
here nor there.

On Mon, May 1, 2017 at 11:29 PM, Xiaodi Wu via swift-evolution < >>>> swift-evolution@swift.org> wrote:

On Mon, May 1, 2017 at 9:52 PM, Karl Wagner <razielim@gmail.com> >>>>> wrote:

> On 2 May 2017, at 04:44, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
>
> Does this gain something by being part of the standard library as
opposed to being built on top of it?

Well, somebody thought repeatElement<T> was general enough to make
part of the standard library. If we’re going to allow repeating a single
item as a Collection, we might as well allow generalise it to repeating any
Collection in a loop (including a CollectionOfOne, which is the existing
use-case).

That doesn't answer the question, though: does the feature you
propose--repeating any instance of Collection in a loop--gain anything by
being a part of the standard library rather than an extension to it?

There are _many_ useful algorithms that can be implemented on top of
the standard library and can be of general use; nonetheless, they aren't a
part of the standard library. IIUC, it's not because people just haven't
had the time to flesh it out; rather, it is a deliberate choice to have a
small, narrowly focused standard library. The philosophy, as I understand
it, is to make it convenient for users to roll their own conveniences
rather than providing all the bits and bobs in the library itself.

One of the points of differentiation between standard library and
Foundation is said to be whether something is necessary to support a core
language feature, in which case it goes into the standard library. As a
consequence, there are less commonly used parts of the standard library
which are there because they support other (decidedly not esoteric) parts
of the standard library and also happen to have some plausible public uses.
Taking a quick look into the repository, for instance, `repeatElement` is
used in the implementation of `UnicodeScalar`. However, just because
someone determined that `repeatElement` is worth making a public API (since
it's going to be in the standard library whether or not it's public),
doesn't _automatically_ mean that a generalization of it should be included
in the library as well.

Personally, I usually want to repeat a collection of things far more

often than I want to repeat an individual thing. It annoys me that the
standard library only provides the one I almost never need.

There are many facilities that the standard library does not provide.
Heck, we don't even have left padding for strings! (JavaScript reference,
for those following along.) Is there something about this particular
feature that makes its not being a part of the standard library uniquely
problematic?

Additionally, it could help remove the top-level “repeatElement”

function, which I know irritates some people who would rather us not have
any top-level functions in the standard library.

With source stability as a goal, the bar for removal isn't "irritates
some people." I actively use this function and there's no justification at
all for breaking it. Frankly, I cannot see removal of top-level functions
simply because they are top-level to be in scope essentially ever. So let's
subset that out of this discussion.

_______________________________________________
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

So, having played with this for a bit, it's not clear to me that a more
elaborate implementation of `cycle` functionality would be measurably
beneficial over a barebones one.

Documentation for `Sequence` clearly indicates that `dropLast` and `suffix`
must not be used on infinite sequences. The same can be said to be obvious
for `map`, `split`, and the current incarnation of `filter` because these
functions return arrays. All other protocol requirements except
`drop(while:)` behave as expected with their default implementation.

There is an improvement possible for `drop(while:)` in that it can be made
to return instead of looping forever if the predicate matches every value.
However, numerous protocol extension methods that can be shadowed but not
overridden have the same issue, and the true solution to that problem is
not within the scope of an additive change (it'd require re-designing
`Sequence` itself--for overall questionable gain, I think).

With that in mind, I'd suggest that we're not looking at much more than
this:


extension Collection {

  public func cycled() -> Cycle<Self> {

    return Cycle(self)

  }

}

public struct Cycle<T : Collection> {

  public let repeatedValues: T

  internal var _iterator: T.Iterator

  internal init(_ _repeatedValues: T) {

    self.repeatedValues = _repeatedValues

    self._iterator = _repeatedValues.makeIterator()

  }

}

extension Cycle : IteratorProtocol, Sequence {

  public var underestimatedCount: Int {

    return repeatedValues.count > 0 ? Int.max : 0

  }

  public mutating func next() -> T.Iterator.Element? {

    if let next = _iterator.next() { return next }

    _iterator = repeatedValues.makeIterator()

    return _iterator.next()

  }

}
···

On Tue, May 2, 2017 at 12:45 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Very useful links. Clearly, `cycle` is a related topic. It's at once more
general, in that it would operate on sequences and produce an infinite
sequence, and much more tricky to implement, as evidenced by the extensive
discussion on support for cycling infinite sequences. Both of those factors
could arguably change the balance in terms of thresholds for inclusion in
the standard library.
On Tue, May 2, 2017 at 11:40 Ole Begemann via swift-evolution < > swift-evolution@swift.org> wrote:

On 02.05.2017 18:33, Ole Begemann via swift-evolution wrote:

For reference, here are some links to previous discussions on related
topics:

1) Kevin Ballard in December 2015: Proposal: CollectionType.cycle
property for an infinite sequence
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151228/004635.html&gt;

2) Ben Cohen in February 2016: Sequence/Collection Enhancements
<https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170213/032120.html&gt;
(one of the enhancements that Ben proposed to consider for adding to the
standard library is a cycle method for Collection and/or Sequence. I
don't think there is a more specific proposal for this yet, but at least we
know it's on the core team's radar.

This should be *February 2017*, of course. Sorry.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution