[Review] Remove C-style for-loops with conditions and incrementers


(Denis Nikitenko) #1

- What is your evaluation of the proposal?

Overall, I think it is a good long-term idea. However, if it is implemented at this point, with no other changes to the language, I believe its negative side effects would outweigh its benefits. I think we should wait until the language evolves several features that mitigate the problems that the immediate removal of the C-style for-loop would introduce.

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

I do not think so. for-loops can lead to errors, such as stepping past the end of an array, but while and do-repeat loops have the same problem. They can also seem somewhat old-fashioned. On the other hand, for-in loops are a clean solution for iterating through an entire collection, or values on a specific interval from n1 to n2, where n1 < n2. However, with the current language features, they are not nearly as clean in several cases that I describe below.

Removal of traditional for-loops would make Swift awkward for implementing many imperative numerical algorithms, where stepping from a value to a value by a custom step occurs rather commonly: you regularly count up and down, have unusual ways of incrementing/decrementing the counter, want to sometimes skip loops, etc.. Functional algorithms are not affected by this, but Swift focuses on imperative programming, with some limited support for functional patterns.

I believe that removal of traditional for loops would also be detrimental in using Swift as a teaching language. Most computer science books often describe (imperative) algorithms using for-loops, either in pseudocode or using C-style syntax. Removal of for loops would make in difficult for people learning programming - or, more generally, computer science, mathematics, and engineering - to make a jump to Swift. Solutions to the problems posed by removing for-loops either involve somewhat esoteric features such as stride() and the defer statement, or rely on the while-loop, which has all the dangers of the for-loop, but makes counting loops less readable.

Some specific examples of difficulties created by removing traditional for-loops:
1) Counting from n1 to n2 where n1 > n2:
We can create a loop "for i in 0…5 { … }". However, there is a lack of symmetry in how the intervals are implemented, and there is no way to create a loop "for i in 5…0 {…}” without calling the reverse() function on the range, using stride(), or switching to a while-loop.

2) There is no clean, concise way to step by increments other than 1. Both while-loops and stride() work. However, while-loops spread the control variables of the loop over multiple lines of code or require defer() to keep the counter close to the loop condition, which is a rather advanced language feature. On the other hand, stride(), is useful but also rather obscure language feature, which is not even mentioned in the Swift iBook.

3) There is no way to create a "for i in n…m {…}", where sometimes m < n and the loop is skipped. This might not be everyone’s cup of tea, but many numerical algorithms rely on this and are presented this way in the literature. If we remove “traditional” for-loops, we instantly place a roadblock for someone who learned Swift as the first language and wants to play around with new algorithms, or whose background is the C-familty of languages.

Now, all of these are probably corner cases for the for-loop. However, all of them pop up regularly in some application areas. For example, I was reviewing a linear algebra book that I want my students to use next semester in a first year undergraduate course. It had pseudocode for a simple LU decomposition algorithm (with no row switching). I decided to implement it in Swift without the “traditional” for-loops. I immediately ran into two of the above issues:

- counting down by 1 required (0…n).reverse(), which seemed unnecessarily verbose
- loops that are sometimes skipped required either:
--- an if-statement preceding a for-loop, which lead to a lot of unnecessary indentation in multiple nested for-loops
--- a while-loop, which spread loop control variables all over my code
--- for-in with stride(), which, while avery useful, is a poorly documented and rather advanced language feature, unfamiliar to many of potentials learners of Swift, both beginners and professionals.

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

It could, but it would need to be implemented in concert with updating and expanding some other language features. Updating Swift intervals to allow 5…0 solves one set of problems. Introducing some form of concise "from-to-by” expression should solve the rest. For now, however, I believe this proposal would introduce more problems that it would solve.

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

I am familiar with:
- C-family of languages (C, C++,Objective-C, Java,and C#), all of which either only use C-style for-loops, or have both for and for-in loops
- Numerical languages: Matlab and R. Both have very flexible and expressive for-loops that support different ranges, boundaries, increments, etc. I think something along these lines - a clean, smart, flexible for-in - could be a good replacement for an old C-style for-loop.
- Scheme. As a Lisp dialect, this language is utterly different from Swift, so I can’t make a direct comparison.

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

I have read the original proposal, and have closely followed the discussions on this list. I have looked through my own code, as well as some common algorithms, to see how easily they would be implemented without C-style for-loops. I have also discussed this with my colleagues, whose background is either academic, or involves working as programmers in the gaming industry. Their comments closely resembled mine.

I would like to thank the Swift team and the community for opening these healthy discussions!

cheers,

Denis