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

Dmitri Gribenko gribozavr at gmail.com
Mon Dec 7 16:31:57 CST 2015


Thank you for the investigation, Nate!

On Mon, Dec 7, 2015 at 2:03 PM, Nate Cook <natecook at gmail.com> wrote:
> It looks like the standard library has between ten and twenty "for var" instances (depends on if you count before or after de-gybbing), that fall into four categories:
>
> 1) for var i = 0; i < length; i++ { ...
>
> These are the most prevalent (and would be everywhere else), and are easily replaced by "for i in 0 ..< length" or "for i in x.indices".
>
> 2) for var i = length; --i >= 0; { ...
>
> This is a "count-down" loop, and isn't handled that well in Swift. The "guessing" translation is both wrong and fails to compile ("for i in length ... 0"), another attempt compiles but is easy to get wrong:
>
> for length.stride(to: 0, by: -1) { // wrong, includes length but not zero
> for length.stride(through: 0, by: -1) { // wrong, still includes length
> for (length - 1).stride(through: 0, by: -1) { // works, but people have switched back to Java by now
>
> Probably the best practice is to use reverse() on the range, since then you'd be using the same method on a "range literal", the indices range, or a collection:
>
> for (0 ..< length).reverse() { ...
>
> 3) for var i = 0; i != n && p != limit; i++ { ...
>
> This style *looks* like #1 but hides a second condition -- it's very easy for a newcomer to come to code with this construct and miss second part of the termination case. Far better to refactor this so the second condition is explicit:
>
> for i in 0 ..< n {
>   guard p != limit else { break }
>   ...
> }
>
> 4) for var x = foo(y); x.isNotFinished(); x = foo(x) { ...
>
> These can be refactored into while loops without much trouble. Your concern below about continue statements is well-founded. What we might call a "while-defer" loop solves that (though I'm not crazy about the construct):
>
> var x = foo(y)
> while x.isNotFinished() {
>   defer { x = foo(x) }
>   ...
> }
>
> That method has the added benefit of putting the test and the "increment" right in one place at the top of the loop. There's a slight difference in that the deferred increment gets executed after a "break", unlike the last statement of a "for var ; ;" loop.
>
> Nate
>
>
>> On Dec 7, 2015, at 3:07 PM, Dmitri Gribenko via swift-evolution <swift-evolution at swift.org> wrote:
>>
>> Hi,
>>
>> My biggest concern with the proposal is the lack of data regarding
>> equivalents for existing C-style for loops.  Note that I'm not talking
>> about code that uses C-style for loops in cases where a superior
>> construct exists in Swift, for example, `for i in myArray.indices`.
>> I'm interested in seeing cases not covered by that.
>>
>> For example, it would be good if someone took a look at "git grep 'for
>> var' stdlib/" and submitted a PR that converts all those loops.  If
>> that results in readability improvements, it would be a great PR
>> regardless of the decision on this proposal.
>>
>> Another concern of mine is the equivalent of C-style for loops with
>> 'continue' statements in them.  The only equivalent based on 'while' I
>> can think of duplicates the increment portion of the loop.
>>
>> Dmitri
>>
>> --
>> main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
>> (j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr at gmail.com>*/
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>



-- 
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr at gmail.com>*/


More information about the swift-evolution mailing list