[swift-evolution] A (better) Swift Equivalent For The Classical For-Loop With Numeric Scalars

Maximilian Hünenberger m.huenenberger at me.com
Wed Mar 23 05:40:55 CDT 2016


I totally agree with you that the for loop shouldn't be overloaded with keywords. Although a "while" condition could be a reasonable addition since the "breaking" condition is at the top of the for loop not at the bottom. One can benefit from this if the condition is more complex.
But this should be a separate proposal.

- Maximilian

Am 23.03.2016 um 02:25 schrieb Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org>:

>> These may be compact, but some programmer may fell that they are not in control: do these "stdlib" seq(), c.filter() pre-calculate all the entries (wasting precious cpu cycle if one break out early)  or are each value dynamically created? Having an explicit legacy loop format gives a feel of control. So something like
>> 
>> for i from 2 to 1_000_000 by 1 where i % 2 != 0 while foundCount < 5 { print(i); foundCount +=1 }
>> 
>> sounds less magical and seems easier to predict than
>> 
>> for i in 2.stride(to:1_000_000, by:1).filter({ $0 % 2 != 0}).prefix(5) { print(i) }
>> 
>> and is still quite readable, even if it mixes for loop, while loop and even simple condition.
> 
> First of all, this example sucks. There are *many* ways to write it with existing features which would be more understandable than the pile of random code in your `for` loop. Here are a few:
> 
>    for i in stride(from: 2, to: 1_000_000, by: 1) where i % 2 == 0 {
>        print(i)
>        foundCount += 1
>        if foundCount >= 5 { break }
>    }
> 
>    for i in stride(from: 2, to: 1_000_000, by: 2) {
>        print(i)
>        foundCount += 1
>        if foundCount >= 5 { break }
>    }
> 
>    for i in stride(from: 2, to: 1_000_000, by: 2).prefix(5) {
>        print(i)
>    }
> 
> I know you're trying to illustrate some features you'd like on the `for` loop, but by choosing this example you're not realy challenging your proposal enough for its disadvantages to be illustrated well. For instance, one thing `stride` cannot currently do is apply a step that doesn't involve addition, for instance by multiplying the number. But your `by` keyword suffers from the same problem! To really add anything new, your proposal would have to be vastly more complicated than what you describe here. It's not fair to say "look how much simpler this is" while sweeping the actual complexity under the rug.
> 
>> Sorry if the example is a bit dumb as is; but I was too lazy to provide some nice code instead of the simple print.
>> Can anyone tell if the filter.prefix above is lazy and that each number is create one by one?
>> The fact that using 1_000_000 above caused my playground to crash, seems to indicate that the list of number is pre-generated.
> 
> Yes, I can tell you without looking at anything that the second example is greedy. `stride` acts lazy (it returns an instance which, when iterated over, produces the values), but `filter` is greedy unless you explicitly use `lazy`. If you don't know this, you can tell by looking at `filter`'s return type, which is an Array.
> 
> Your "explicit" syntax, on the other hand, seems totally out of control. Where do these features come from? What happens when you find something else you want to do in a loop? Do you invent another keyword and give it a new syntax? This *still* doesn't give you enough flexibility to express a `for` loop which doubles the number; is that going to require a new keyword? How many keywords is it going to take? Is anyone ever going to learn what all these keywords mean? Are you going to have to re-read The Swift Programming Language to decode every moderately complicated `for` loop?
> 
> (And how am I supposed to mentally parse your sea of undifferentiated alphanumerics? Punctuation in a programming language helps you understand the role of each part of it; your proposal's lack of punctuation makes it difficult to read.)
> 
> The function/method-based approach requires a little more syntax and a little more understanding of what's going on. But has huge advantages that I think you're unfairly ignoring:
> 
> * It is simple. The `for` loop itself is quite uncomplicated. The only extra features it has are the `case` clause, which can't be easily duplicated in another way, and the `where` clause, which I've honestly never been totally happy with.
> * It is reusable. Calls like `stride`, `filter` and `prefix` can be used even outside a `for` loop.
> * It is extensible. If you need something new, you can add it, and it will be just as accessible as anything the standard library's designers dreamed up.
> * It is documentable. By using functions and methods instead of keywords, it's easier to look up what a particular feature does.
> * It is sustainable. If we have some kind of really specific looping mechanism like you propose, every little feature we want will need a specific design, evolution proposal, and implementation by the compiler team. That is a completely unrealistic plan. Not even the C `for` loop took this approach—it provided a *general* mechanism for plugging your own logic into a loop.
> 
> Ultimately, piling on new keywords every time you think of a tiny variation is simply bad language design. Taking this approach would be foolhardy.
> 
> -- 
> Brent Royal-Gordon
> Architechies
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution


More information about the swift-evolution mailing list