[swift-evolution] [Review] SE-0045: Add scan, prefix(while:), drop(while:), and iterate to the stdlib

Brent Royal-Gordon brent at architechies.com
Thu Apr 28 23:15:24 CDT 2016

> 	* What is your evaluation of the proposal?

Great and necessary. I particularly like that the combination of `iterate(1, apply: { $0 * 2 }).prefix(while: { $0 < 100_000 })` mimics the abilities of the old C-style for loop.

Bikeshedding time!

* * *

I really like the `reduce`/`reductions` pairing instead of `reduce`/`scan`; it does a really good job of explaining the relationship between the two functions. I also think the `startingWith` label may be a good idea, although if we do that, we might want to change the second label to `combiningWith`.

* * *

I believe that `prefix(while:)` and `dropFirst(while:)` would be most consistent with the current standard library, but frankly, I consider that an indictment of the current names.

`skip` is better than `drop`, but they are both pigs; one's just wearing lipstick. The whole area of APIs which grab subsets of Sequences or Collections could use some renaming. It is rife with both inconsistencies (`prefix(_:)` and `dropFirst(_:)` are inverses, but look unrelated) and names which appear to mutate but don't (all the `drop` APIs). These APIs are currently grandfathered in with the term-of-art rule, which I normally agree with, but I think the results here are so bad that we can't let them stand.

I would suggest that we systematically rename these APIs to achieve a consistent, non-verb-based pattern which the new APIs can slot into nicely:

	first								// Currently first
	prefix(_: Int)						// Currently prefix(_:)
	prefix(while: Element -> Bool)			// Proposed as prefix(while:)
	afterFirst() or afterFirst				// Currently dropFirst()
	afterPrefix(_: Int)					// Currently dropFirst(_:)
	afterPrefix(while: Element -> Bool)		// Proposed as drop(while:)

	last								// Currently last
	suffix(_: Int)						// Currently suffix(_:)
	suffix(while: Element -> Bool)			// Unproposed
	beforeLast() or beforeLast			// Currently dropLast()
	beforeSuffix(_: Int)					// Currently dropLast(_:)
	beforeSuffix(while: Element -> Bool)	// Unproposed

	before(to: Index)					// Currently prefix(upTo:)
	before(through: Index)				// Currently prefix(through:)
	after(to: Index)						// Unproposed?
	after(through: Index)				// suffix(from:)?

Several of these APIs are listed as "unproposed"; they are neither in the current standard library, nor in this proposal. I am not suggesting we add them, but simply showing how they would be named if they *were* provided.

If the core team wants to protect `dropFirst` and `dropLast` as terms of art, I think our best alternative is to make `first` and `last` nullary methods, and rename the `prefix` methods to `first` and `suffix` to `last`. It seems like the decision to make `first` and `last` properties was a little bit uncertain to begin with; I think the naming issues here tip the scales.

In any case, though, the core team might prefer to consider this relatively large renaming as a separate proposal. If so, as I said, I think `prefix(while:)` and `dropFirst(while:)` are the best matches for the current APIs.

* * *

I think `iterate` is the best basic approach to the name. My own prototypes used `induce` since the sequence was produced by induction from a starting value and transformation function, but this approach was too clever by half: people were confused by the name until it was explained, and then they thought it was clever but had trouble remembering it.

There is precedent in the current standard library for using an imperative verb to lazily construct a list: the `repeatElement(_:count:)` function. However, if we don't like that for this case, an alternative is to use the noun `iteration`. And if we're going with the noun, well, that suggests that what we really want to define is not a function, but a type:

	struct Iteration<T>: Sequence {
		init(start startingValue: T, apply transformation: T -> T)

This reads fairly well in common uses:

	for i in Iteration(start: 1, apply: { $0 * 2 }) { … }

> 	* Is the problem being addressed significant enough to warrant a change to Swift?

Yes. As I mentioned before, the combination of `iterate` and `prefix(while:)` is particularly important.

> 	* Does this proposal fit well with the feel and direction of Swift?

Yes; these fill important holes in our ability to create and manipulate sequences.

> 	* If you have you used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Most languages I've used which have these features give them terrible names; these names help make them less accessible. I'm hoping that Swift will do better.

> 	* How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Read the review a few times, independently re-invented about half of it in various discussions and explorations of the C-style for loop removal.

Brent Royal-Gordon

More information about the swift-evolution mailing list