Add a while clause to for loops

That’s why I said “potentially less elegant”, some people might prefer `where` over `guard`. This proposal would give them the choice (in very specific situations) to use `where` rather than `guard` if they don’t want to sacrifice performance.

···

On Wed, Jun 8, 2016 at 1:35 PM, Tim Vermeulen via swift-evolution<swift-evolution@swift.org(mailto:swift-evolution@swift.org)>wrote:
> This is a really strong argument in my opinion. If we don’t add a `while` to for loops, then in some situations we will have to rewrite a `where` clause to something potentially less elegant, given that we don’t want to give up performance.
I disagree. I argue that what you call "less elegant", namely if (or guard) inside the loop, is the most elegant solution.

>
> >IMO `.prefix` is just not the equal alternative for as proposed `while` :
> >in case of 'while' expression `number<4_000_000` will be calculated
> >*only* for those who `number % 2 == 0`. In case of `prefix` - the
> >expression will be processed for each `number` and only after this filtered
> >by `number % 2`. Let's assume we need to check for some
> >veryExpensiveTest(number):
> >
> >for number in fibonacci where number % 2 == 0 while
> >veryExpensiveTest(number) {}
> >
> >let numbers = fibonacci.prefix { veryExpensiveTest($0) }
> >for number in numbers where number % 2 == 0 {}
> >
> >So, `while` for `for` loops just can't be always replaced with `prefix`
> >
> >On 08.06.2016 2:02, Xiaodi Wu via swift-evolution wrote:
> >>On Tue, Jun 7, 2016 at 5:11 PM, Tim Vermeulen<tvermeulen@me.com(mailto:tvermeulen@me.com) > > >><mailto:tvermeulen@me.com>>wrote:
> >>
> >>I’ve been thinking about this for a bit now, and I think it would make
> >>most sense to evaluate these clauses from left to right. However, cases
> >>where the order matters are very uncommon, and I would rather have the
> >>power to choose which clause is evaluated first than to have a forced
> >>default order. Either way I don’t see this as a reason not to allow
> >>combining the two clauses because IMO it can lead to some very clean
> >>code. For instance, say we want to loop through all even fibonacci
> >>numbers below 4 million (see problem #2 from project euler), we could
> >>do this:
> >>
> >>`for number in fibonacci where number % 2 == 0 while number<4_000_000
> >>{ }`
> >>
> >>
> >>This statement looks like spaghetti to me. I would not at all support
> >>extending the language to permit it. Do you really think it's more readable
> >>than going step-by-step?
> >>
> >>```
> >>let numbers = fibonacci.prefix { $0<4_000_000 }
> >>for number in numbers where number % 2 == 0 {
> >>// ...
> >>}
> >>```
> >>
> >>or just:
> >>
> >>```
> >>let numbers = fibonacci.prefix { $0<4_000_000 }
> >>let evens = numbers.filter { $0 % 2 == 0 }
> >>for number in evens {
> >>// ...
> >>}
> >>```
> >>
> >>
> >>I could have ordered the two clauses in any way I want. If combining
> >>the clauses weren’t allowed, I’d have to put (at least) one of them
> >>inside the block, which would be a (minor) pain.
> >>
> >>I don’t currently have a very strong opinion about the order of
> >>evaluation, so I might be convinced otherwise. But combining the two
> >>clauses is so powerful that I don’t think it’s worth to get rid of just
> >>because of an edge case.
> >>
> >>>It may be workable if you can have only one or the other, but mixing and matching them as proposed above would be a world of hurt:
> >>>
> >>>```
> >>>for foo in bar where condition1 while condition2 { ... }
> >>>```
> >>>
> >>>If condition1 and condition2 both evaluate to true, then whether you continue or break would depend on the relative order of where and while; for generality, you would want to allow both `for...in...where...while` and `for...in...while...where`, and likely `for...in...while...where...while`, etc. There is nothing in the meaning of those words that would suggest that `while...where` behaves differently from `where...while`, etc. This is why words like "break" and "continue" are IMO far superior.
> >>>
> >>>
> >>>On Tue, Jun 7, 2016 at 2:34 PM, Erica Sadun<erica@ericasadun.com(mailto:erica@ericasadun.com) > > >><mailto:erica@ericasadun.com>(mailto:erica@ericasadun.com > > >><mailto:erica@ericasadun.com>)>wrote:
> >>>>
> >>>>>On Jun 7, 2016, at 1:16 PM, Tim Vermeulen via swift-evolution<swift-evolution@swift.org(mailto:swift-evolution@swift.org) > > >><mailto:swift-evolution@swift.org>(mailto:swift-evolution@swift.org > > >><mailto:swift-evolution@swift.org>)>wrote:
> >>>>>>The meaning of the proposed while is not at all a pair for where, since where clauses in while loops would do the same thing as while clauses in for loops. That's crazy.
> >>>>>
> >>>>>It sounds crazy, but it’s the nature of the while loop. A where clause in a while loop also has a different result than a where clause in a for loop.
> >>>>
> >>>>The where_clause appears in the for in statement
> >>>>
> >>>>for_in_statement : 'for' 'case'? pattern 'in' expression where_clause? code_block
> >>>>
> >>>>It's syntactic sugar because the expression can be already be limited through functional chaining of some sort or another. At the same time, it's nice and pleasant to have `where` and I'm not itching to throw it out. The same courtesy could be easily extend to `when` (because I don't really want to use the `while` keyword here, but I could easily be convinced otherwise because I don't have a strong stance either way):
> >>>>
> >>>>for_in_statement : 'for' 'case'? pattern 'in' expression (where_clause | when_clause)? code_block
> >>>>when_clause : 'when' expression
> >>>>
> >>>>and again it could be nice and pleasant to have, although not necessary. The question comes down to how much does the language benefit by this sugar.
> >>>>
> >>>>I'd say that in both cases, combining chaining and statements is
> >>marginallyless goodthan either using standalone chaining or statements
> >>without chaining. But as I say this, I know as a fact, I fully intend
> >>to use `sequence(_:, next:).take(while:)` with for0in statements, so
> >>I'm starting from a hypocritical vantage point.
> >>>>
> >>>>To summarize, I'm more +0.01 than I am -0.01 on this.
> >>>>
> >>>>-- E
> >>>>p.s. Sorry, wux
> >>
> >>
> >>
> >>
> >>_______________________________________________
> >>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(mailto:swift-evolution@swift.org)
> https://lists.swift.org/mailman/listinfo/swift-evolution

I think it would be valuable to defer this discussion until after WWDC to see how SE-0099 does. The core team's response to while exfoliation will greatly affect both how this suggestion goes.

(As is, if this moves forward, I'd say go with either where or while but not both, or eliminate while entirely.)

--- E

···

On Jun 8, 2016, at 1:07 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:
I should add, on the topic of removing `where`, there would be a higher threshold for a successful proposal and I would have to convince people that the `where` clause is actually harmful. I do wonder if I could succeed in that endeavor. But when it comes to adding something like `while`, you've yet to convince me it offers more than just stylistic choice. IMO, that is insufficient for a proposal as consequential as adding syntax to the language itself (a much more serious addition than changing API in the stdlib, for example).

That's actually also a part of what's proposed in SE-0099.

···

On Wed, Jun 8, 2016 at 1:51 PM, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

On Wed, Jun 8, 2016 at 1:38 AM, Haravikk via swift-evolution < > swift-evolution@swift.org> wrote:

I’m not sure I agree that this is confusing, a little extra to learn for
new programmers perhaps but I think it’s fairly intuitive:

while let value = foo.next() where someCondition(value) { … }

This reads to me as “repeat the following block until this fails to be
true”, the conditional binding in this case fails to be true if
someCondition(value) isn’t true, so the loop ends. I think the key thing
here is that the where clause is for the conditional binding and not the
loop itself, so in this respect it behaves exactly like an if or guard
statement.

So, I think it might be much clearer if, similarly to how there's a
discussion about unifying "where" vs. "comma" conditions in guard/if, we
could do the same here.

    while let value = foo.next(), let something = value.property,
something == 4 { ... }

(Apologies if this has been said; I haven't followed the whole thread
closely.)

That’s why I said “potentially less elegant”, some people might prefer
`where` over `guard`. This proposal would give them the choice (in very
specific situations) to use `where` rather than `guard` if they don’t want
to sacrifice performance.

Since Swift strives to be an opinionated language without dialects, there
shouldn't be more "choice" but rather one general solution, IMO. Since
`guard` doesn't sacrifice performance and is the most general, I would
oppose adding the option of `while` to offer more choice.

···

On Wed, Jun 8, 2016 at 1:58 PM, Tim Vermeulen <tvermeulen@me.com> wrote:

> On Wed, Jun 8, 2016 at 1:35 PM, Tim Vermeulen via swift-evolution< > swift-evolution@swift.org(mailto:swift-evolution@swift.org)>wrote:
> > This is a really strong argument in my opinion. If we don’t add a
`while` to for loops, then in some situations we will have to rewrite a
`where` clause to something potentially less elegant, given that we don’t
want to give up performance.
> I disagree. I argue that what you call "less elegant", namely if (or
guard) inside the loop, is the most elegant solution.
>
> >
> > >IMO `.prefix` is just not the equal alternative for as proposed
`while` :
> > >in case of 'while' expression `number<4_000_000` will be calculated
> > >*only* for those who `number % 2 == 0`. In case of `prefix` - the
> > >expression will be processed for each `number` and only after this
filtered
> > >by `number % 2`. Let's assume we need to check for some
> > >veryExpensiveTest(number):
> > >
> > >for number in fibonacci where number % 2 == 0 while
> > >veryExpensiveTest(number) {}
> > >
> > >let numbers = fibonacci.prefix { veryExpensiveTest($0) }
> > >for number in numbers where number % 2 == 0 {}
> > >
> > >So, `while` for `for` loops just can't be always replaced with
`prefix`
> > >
> > >On 08.06.2016 2:02, Xiaodi Wu via swift-evolution wrote:
> > >>On Tue, Jun 7, 2016 at 5:11 PM, Tim Vermeulen<tvermeulen@me.com > (mailto:tvermeulen@me.com) > > > >><mailto:tvermeulen@me.com>>wrote:
> > >>
> > >>I’ve been thinking about this for a bit now, and I think it would
make
> > >>most sense to evaluate these clauses from left to right. However,
cases
> > >>where the order matters are very uncommon, and I would rather have
the
> > >>power to choose which clause is evaluated first than to have a forced
> > >>default order. Either way I don’t see this as a reason not to allow
> > >>combining the two clauses because IMO it can lead to some very clean
> > >>code. For instance, say we want to loop through all even fibonacci
> > >>numbers below 4 million (see problem #2 from project euler), we could
> > >>do this:
> > >>
> > >>`for number in fibonacci where number % 2 == 0 while number<4_000_000
> > >>{ }`
> > >>
> > >>
> > >>This statement looks like spaghetti to me. I would not at all support
> > >>extending the language to permit it. Do you really think it's more
readable
> > >>than going step-by-step?
> > >>
> > >>```
> > >>let numbers = fibonacci.prefix { $0<4_000_000 }
> > >>for number in numbers where number % 2 == 0 {
> > >>// ...
> > >>}
> > >>```
> > >>
> > >>or just:
> > >>
> > >>```
> > >>let numbers = fibonacci.prefix { $0<4_000_000 }
> > >>let evens = numbers.filter { $0 % 2 == 0 }
> > >>for number in evens {
> > >>// ...
> > >>}
> > >>```
> > >>
> > >>
> > >>I could have ordered the two clauses in any way I want. If combining
> > >>the clauses weren’t allowed, I’d have to put (at least) one of them
> > >>inside the block, which would be a (minor) pain.
> > >>
> > >>I don’t currently have a very strong opinion about the order of
> > >>evaluation, so I might be convinced otherwise. But combining the two
> > >>clauses is so powerful that I don’t think it’s worth to get rid of
just
> > >>because of an edge case.
> > >>
> > >>>It may be workable if you can have only one or the other, but
mixing and matching them as proposed above would be a world of hurt:
> > >>>
> > >>>```
> > >>>for foo in bar where condition1 while condition2 { ... }
> > >>>```
> > >>>
> > >>>If condition1 and condition2 both evaluate to true, then whether
you continue or break would depend on the relative order of where and
while; for generality, you would want to allow both
`for...in...where...while` and `for...in...while...where`, and likely
`for...in...while...where...while`, etc. There is nothing in the meaning of
those words that would suggest that `while...where` behaves differently
from `where...while`, etc. This is why words like "break" and "continue"
are IMO far superior.
> > >>>
> > >>>
> > >>>On Tue, Jun 7, 2016 at 2:34 PM, Erica Sadun<erica@ericasadun.com > (mailto:erica@ericasadun.com) > > > >><mailto:erica@ericasadun.com>(mailto:erica@ericasadun.com > > > >><mailto:erica@ericasadun.com>)>wrote:
> > >>>>
> > >>>>>On Jun 7, 2016, at 1:16 PM, Tim Vermeulen via swift-evolution< > swift-evolution@swift.org(mailto:swift-evolution@swift.org) > > > >><mailto:swift-evolution@swift.org>(mailto:swift-evolution@swift.org > > > >><mailto:swift-evolution@swift.org>)>wrote:
> > >>>>>>The meaning of the proposed while is not at all a pair for
where, since where clauses in while loops would do the same thing as while
clauses in for loops. That's crazy.
> > >>>>>
> > >>>>>It sounds crazy, but it’s the nature of the while loop. A where
clause in a while loop also has a different result than a where clause in a
for loop.
> > >>>>
> > >>>>The where_clause appears in the for in statement
> > >>>>
> > >>>>for_in_statement : 'for' 'case'? pattern 'in' expression
where_clause? code_block
> > >>>>
> > >>>>It's syntactic sugar because the expression can be already be
limited through functional chaining of some sort or another. At the same
time, it's nice and pleasant to have `where` and I'm not itching to throw
it out. The same courtesy could be easily extend to `when` (because I don't
really want to use the `while` keyword here, but I could easily be
convinced otherwise because I don't have a strong stance either way):
> > >>>>
> > >>>>for_in_statement : 'for' 'case'? pattern 'in' expression
(where_clause | when_clause)? code_block
> > >>>>when_clause : 'when' expression
> > >>>>
> > >>>>and again it could be nice and pleasant to have, although not
necessary. The question comes down to how much does the language benefit by
this sugar.
> > >>>>
> > >>>>I'd say that in both cases, combining chaining and statements is
> > >>marginallyless goodthan either using standalone chaining or
statements
> > >>without chaining. But as I say this, I know as a fact, I fully intend
> > >>to use `sequence(_:, next:).take(while:)` with for0in statements, so
> > >>I'm starting from a hypocritical vantage point.
> > >>>>
> > >>>>To summarize, I'm more +0.01 than I am -0.01 on this.
> > >>>>
> > >>>>-- E
> > >>>>p.s. Sorry, wux
> > >>
> > >>
> > >>
> > >>
> > >>_______________________________________________
> > >>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(mailto:swift-evolution@swift.org)
> > https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>

That’s why I said “potentially less elegant”, some people might prefer
`where` over `guard`. This proposal would give them the choice (in very
specific situations) to use `where` rather than `guard` if they don’t want
to sacrifice performance.

Since Swift strives to be an opinionated language without dialects, there
shouldn't be more "choice" but rather one general solution, IMO. Since
`guard` doesn't sacrifice performance and is the most general, I would
oppose adding the option of `while` to offer more choice.

I should add, on the topic of removing `where`, there would be a higher
threshold for a successful proposal and I would have to convince people
that the `where` clause is actually harmful. I do wonder if I could succeed
in that endeavor. But when it comes to adding something like `while`,
you've yet to convince me it offers more than just stylistic choice. IMO,
that is insufficient for a proposal as consequential as adding syntax to
the language itself (a much more serious addition than changing API in the
stdlib, for example).

···

On Wed, Jun 8, 2016 at 2:01 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Wed, Jun 8, 2016 at 1:58 PM, Tim Vermeulen <tvermeulen@me.com> wrote:

> On Wed, Jun 8, 2016 at 1:35 PM, Tim Vermeulen via swift-evolution< >> swift-evolution@swift.org(mailto:swift-evolution@swift.org)>wrote:
> > This is a really strong argument in my opinion. If we don’t add a
`while` to for loops, then in some situations we will have to rewrite a
`where` clause to something potentially less elegant, given that we don’t
want to give up performance.
> I disagree. I argue that what you call "less elegant", namely if (or
guard) inside the loop, is the most elegant solution.
>
> >
> > >IMO `.prefix` is just not the equal alternative for as proposed
`while` :
> > >in case of 'while' expression `number<4_000_000` will be calculated
> > >*only* for those who `number % 2 == 0`. In case of `prefix` - the
> > >expression will be processed for each `number` and only after this
filtered
> > >by `number % 2`. Let's assume we need to check for some
> > >veryExpensiveTest(number):
> > >
> > >for number in fibonacci where number % 2 == 0 while
> > >veryExpensiveTest(number) {}
> > >
> > >let numbers = fibonacci.prefix { veryExpensiveTest($0) }
> > >for number in numbers where number % 2 == 0 {}
> > >
> > >So, `while` for `for` loops just can't be always replaced with
`prefix`
> > >
> > >On 08.06.2016 2:02, Xiaodi Wu via swift-evolution wrote:
> > >>On Tue, Jun 7, 2016 at 5:11 PM, Tim Vermeulen<tvermeulen@me.com >> (mailto:tvermeulen@me.com) >> > > >><mailto:tvermeulen@me.com>>wrote:
> > >>
> > >>I’ve been thinking about this for a bit now, and I think it would
make
> > >>most sense to evaluate these clauses from left to right. However,
cases
> > >>where the order matters are very uncommon, and I would rather have
the
> > >>power to choose which clause is evaluated first than to have a
forced
> > >>default order. Either way I don’t see this as a reason not to allow
> > >>combining the two clauses because IMO it can lead to some very clean
> > >>code. For instance, say we want to loop through all even fibonacci
> > >>numbers below 4 million (see problem #2 from project euler), we
could
> > >>do this:
> > >>
> > >>`for number in fibonacci where number % 2 == 0 while
number<4_000_000
> > >>{ }`
> > >>
> > >>
> > >>This statement looks like spaghetti to me. I would not at all
support
> > >>extending the language to permit it. Do you really think it's more
readable
> > >>than going step-by-step?
> > >>
> > >>```
> > >>let numbers = fibonacci.prefix { $0<4_000_000 }
> > >>for number in numbers where number % 2 == 0 {
> > >>// ...
> > >>}
> > >>```
> > >>
> > >>or just:
> > >>
> > >>```
> > >>let numbers = fibonacci.prefix { $0<4_000_000 }
> > >>let evens = numbers.filter { $0 % 2 == 0 }
> > >>for number in evens {
> > >>// ...
> > >>}
> > >>```
> > >>
> > >>
> > >>I could have ordered the two clauses in any way I want. If combining
> > >>the clauses weren’t allowed, I’d have to put (at least) one of them
> > >>inside the block, which would be a (minor) pain.
> > >>
> > >>I don’t currently have a very strong opinion about the order of
> > >>evaluation, so I might be convinced otherwise. But combining the two
> > >>clauses is so powerful that I don’t think it’s worth to get rid of
just
> > >>because of an edge case.
> > >>
> > >>>It may be workable if you can have only one or the other, but
mixing and matching them as proposed above would be a world of hurt:
> > >>>
> > >>>```
> > >>>for foo in bar where condition1 while condition2 { ... }
> > >>>```
> > >>>
> > >>>If condition1 and condition2 both evaluate to true, then whether
you continue or break would depend on the relative order of where and
while; for generality, you would want to allow both
`for...in...where...while` and `for...in...while...where`, and likely
`for...in...while...where...while`, etc. There is nothing in the meaning of
those words that would suggest that `while...where` behaves differently
from `where...while`, etc. This is why words like "break" and "continue"
are IMO far superior.
> > >>>
> > >>>
> > >>>On Tue, Jun 7, 2016 at 2:34 PM, Erica Sadun<erica@ericasadun.com >> (mailto:erica@ericasadun.com) >> > > >><mailto:erica@ericasadun.com>(mailto:erica@ericasadun.com >> > > >><mailto:erica@ericasadun.com>)>wrote:
> > >>>>
> > >>>>>On Jun 7, 2016, at 1:16 PM, Tim Vermeulen via swift-evolution< >> swift-evolution@swift.org(mailto:swift-evolution@swift.org) >> > > >><mailto:swift-evolution@swift.org>(mailto:swift-evolution@swift.org >> > > >><mailto:swift-evolution@swift.org>)>wrote:
> > >>>>>>The meaning of the proposed while is not at all a pair for
where, since where clauses in while loops would do the same thing as while
clauses in for loops. That's crazy.
> > >>>>>
> > >>>>>It sounds crazy, but it’s the nature of the while loop. A where
clause in a while loop also has a different result than a where clause in a
for loop.
> > >>>>
> > >>>>The where_clause appears in the for in statement
> > >>>>
> > >>>>for_in_statement : 'for' 'case'? pattern 'in' expression
where_clause? code_block
> > >>>>
> > >>>>It's syntactic sugar because the expression can be already be
limited through functional chaining of some sort or another. At the same
time, it's nice and pleasant to have `where` and I'm not itching to throw
it out. The same courtesy could be easily extend to `when` (because I don't
really want to use the `while` keyword here, but I could easily be
convinced otherwise because I don't have a strong stance either way):
> > >>>>
> > >>>>for_in_statement : 'for' 'case'? pattern 'in' expression
(where_clause | when_clause)? code_block
> > >>>>when_clause : 'when' expression
> > >>>>
> > >>>>and again it could be nice and pleasant to have, although not
necessary. The question comes down to how much does the language benefit by
this sugar.
> > >>>>
> > >>>>I'd say that in both cases, combining chaining and statements is
> > >>marginallyless goodthan either using standalone chaining or
statements
> > >>without chaining. But as I say this, I know as a fact, I fully
intend
> > >>to use `sequence(_:, next:).take(while:)` with for0in statements, so
> > >>I'm starting from a hypocritical vantage point.
> > >>>>
> > >>>>To summarize, I'm more +0.01 than I am -0.01 on this.
> > >>>>
> > >>>>-- E
> > >>>>p.s. Sorry, wux
> > >>
> > >>
> > >>
> > >>
> > >>_______________________________________________
> > >>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(mailto:swift-evolution@swift.org)
> > https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>

> I should add, on the topic of removing `where`, there would be a higher
threshold for a successful proposal and I would have to convince people
that the `where` clause is actually harmful. I do wonder if I could succeed
in that endeavor. But when it comes to adding something like `while`,
you've yet to convince me it offers more than just stylistic choice. IMO,
that is insufficient for a proposal as consequential as adding syntax to
the language itself (a much more serious addition than changing API in the
stdlib, for example).

I think it would be valuable to defer this discussion until after WWDC to
see how SE-0099 does. The core team's response to while exfoliation will
greatly affect both how this suggestion goes.

Probably wise.

···

On Wed, Jun 8, 2016 at 2:31 PM, Erica Sadun <erica@ericasadun.com> wrote:

> On Jun 8, 2016, at 1:07 PM, Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote:

(As is, if this moves forward, I'd say go with either where or while but
not both, or eliminate while entirely.)

--- E

Why would breaking from a loop intuitively use a place analogy and continuing to the next iteration use a time analogy? This is totally made up; hence, it is not intuitive. I make no argument about whether or not it would be conceptually confusing. If you renamed 'break' to 'foo' and 'continue' to 'bar', it would not be intuitive, but you could likewise argue that it's not confusing, in that 'foo' is clearly not 'bar’.

I think it’s quite intuitive, just like how a standard while loop is intuitive. “Execute this loop while this condition holds, for every case where that condition holds.” That’s how I would phrase such an expression in normal English. Doesn’t that make it intuitive? I can’t really switch the meanings of “while” and “where” and still have that sentence make sense.

As I pointed out above with Tim's example, putting it all on one line is absolutely not 'neat'--it reads like spaghetti. That is one major beef I have with this proposal: that it *encourages* writing on one line too many things that, whether you use `where` or not, are much more clearly written on multiple lines. If writing everything on one line is for you the major advantage of this proposal, we could agree on everything else and I would be very much opposed to this proposal on that basis alone.

You could argue that this proposal encourages writing a lot on a single line, but I could argue that not implementing this proposal would encourage people to write stuff like

for number in fibonacci.lazy.filter({ number % 2 == 0 }).prefix(where: { $0 < 4_000_000 }) { }

I would choose `for number in fibonacci where number % 2 == 0 while number < 4_000_000 { }` over the statement above any day. You can break up either into multiple lines for better readability, or you can move the conditions inside the loop, but that’s true no matter if this proposal will be accepted or rejected.

···

On Wed, Jun 8, 2016 at 3:38 AM, Haravikk<swift-evolution@haravikk.me(mailto:swift-evolution@haravikk.me)>wrote:
>
> > On 8 Jun 2016, at 01:54, Xiaodi Wu via swift-evolution<swift-evolution@swift.org(mailto:swift-evolution@swift.org)>wrote:
> >
> > 1) It is spelled out exactly what happens when a condition is met. I no longer have to remember whether the word that describes breaking from a loop uses a place analogy ("where") or a time analogy ("while" or "when”).
> >
> > (You cannot convince me that these words are intuitive when the meaning of "where" changes by context in today's Swift. Now, if you want to propose that these be named "breakif" and "continueif" instead, then I'd agree with you that they're intuitive names, but then they'd also be really ugly.)
> I’m not sure I agree that this is confusing,
Why would breaking from a loop intuitively use a place analogy and continuing to the next iteration use a time analogy? This is totally made up; hence, it is not intuitive. I make no argument about whether or not it would be conceptually confusing. If you renamed 'break' to 'foo' and 'continue' to 'bar', it would not be intuitive, but you could likewise argue that it's not confusing, in that 'foo' is clearly not 'bar'.

> a little extra to learn for new programmers perhaps but I think it’s fairly intuitive:
>
> while let value = foo.next() where someCondition(value) { … }
>
> This reads to me as “repeat the following block until this fails to be true”, the conditional binding in this case fails to be true if someCondition(value) isn’t true, so the loop ends. I think the key thing here is that the where clause is for the conditional binding and not the loop itself, so in this respect it behaves exactly like an if or guard statement. Meanwhile:
>
> for eachValue in theValues where someCondition(eachValue) { … }
>
> Reads as “for everything in theValues do the following if someCondition(eachValue) is also true”, in other words this loop always tries to visit every element of the sequence (a while loop has no implicit awareness of the sequence, it’s really just an if statement that runs over and over). In this case the where clause is part of the loop itself. There may be an argument that where should be renamed on for loops to better distinguish this, but once you consider that there’s no pattern or conditional binding here I think it makes a reasonable amount of sense.
>
> Yes this could be handled by an if/guard statement with continue, and while as proposed here could be done with the same plus a break, but these things come up so often that it just makes a lot of sense to get it all neatly onto one line.
As I pointed out above with Tim's example, putting it all on one line is absolutely not 'neat'--it reads like spaghetti. That is one major beef I have with this proposal: that it *encourages* writing on one line too many things that, whether you use `where` or not, are much more clearly written on multiple lines. If writing everything on one line is for you the major advantage of this proposal, we could agree on everything else and I would be very much opposed to this proposal on that basis alone.

> Chaining methods can do this, but it’s actually less readable IMO, or requires multiple lines to keep it clear which defeats the point.
>
>
For me, encouraging the use of multiple lines is the point. Tim's example demonstrated to me very clearly that clarity is not served by additional sugar to reduce the amount of punctuation on one line; it is served only by putting things on multiple lines. As I said above, I would cringe to read a loop that begins `for foo in bar where something while somethingElse where yetAnotherSomething while againAnotherSomething { ... }`.

> As with where on if/guard statements it’s about keeping the simpler, more common cases as clean and readable as possible. If the re-use of the keyword where on the for loop is confusing then that’s an argument for renaming that, rather than rejecting while or ditching the whole thing IMO. Personally I think it’s okay, you just have to think what the where clause is actually acting upon.
>
> > 3) I have the flexibility to do something between the first if statement and the second if statement, if I want. By placing the break statement at the end of my loop, I could effectively choose to have one more iteration than if I placed it at the beginning of my loop. There is nothing you can do to mimic that choice with your proposed while clause, unless you want to also propose a `for...in...repeat { } while` syntax.
>
> So? Like where clauses this is for the simpler cases, if you want to do something more complex you remain free to use more complex conditionals.
And I was/am a proponent of SE-0099 to remove `where` from if and while loops; and if that succeeds I will definitely solicit comments to remove it from for loops!

> A lot of the time you don’t need this however, so it makes sense to simplify the common case while leaving the complex one just as useful as it is today. Nothing about this proposal would stop you from using if/guard conditions inside the loop.
>
> > 4) This is the perhaps the important point. A beginning programmer--not any of us, presumably, but we were all beginners once--can accomplish everything that he or she desires without learning this new proposed syntax. Almost all texts, I believe, teach if statements before loops, and teach break and continue in the same breath as the loops themselves.
> In terms of teaching there shouldn’t be a problem with just teaching the basic building blocks first, then showing off simplifications later. As with any coding the most important thing is to get the intended behaviour correct, simplifying or optimising the code can always come later.
>
> You could argue the same thing about the shorthands around closures; I’m not sure why but I had trouble with those initially until after I’d worked with them in the more verbose form (with fully named parameters and a return statement) till I started to get the logic behind it, now I can just right a quick closure with the dollar sign shorthand.
Closures are--I'm sure you'd agree--a far more advanced concept than loops. Concepts like closing over a variable are very, very hard. Many useful things can be written without using closures. Not so many things could do without loops. It very much matters that a learner might feel that he or she cannot understand everything about a loop with the handwavy explanation that it'll "come later". One critique of using Java as a starting language is that you are forced to teach your students on day one that the real meaning of the words "public static void main(String args)" will "come later".

>
> A good linter could be written to detect the presence of a simple if/guard right inside the loop and could then suggest the use of where/while as appropriate.

Yes this could be handled by an if/guard statement with continue, and while as proposed here could be done with the same plus a break, but these things come up so often that it just makes a lot of sense to get it all neatly onto one line.

As I pointed out above with Tim's example, putting it all on one line is absolutely not 'neat'--it reads like spaghetti. That is one major beef I have with this proposal: that it *encourages* writing on one line too many things that, whether you use `where` or not, are much more clearly written on multiple lines. If writing everything on one line is for you the major advantage of this proposal, we could agree on everything else and I would be very much opposed to this proposal on that basis alone.

I’m not proposing that every single loop have all of its conditions crushed onto one line, just like I wasn’t when discussing where on the condition clause thread. The usefulness of where and the proposed while is in the common, simple cases, for example:

  for eachValue in theValues while eachValue < 100 where eachValue % 2 == 0 { … }

The alternatives would be:

  for eachValue in theValues {
    guard eachValue < 100 else { break }
    guard eachValue % 2 == 0 else { continue }
    …
  }
  for eachValue in theValues.prefix(while: { $0 < 100 }).filter({ $0 % 2 == 0 }) { … } // Could also be on multiple lines

The former wastes vertical space for what it does IMO; it’s fine if the conditions were more complicated, but since they’re not where/while is ideal. The second isn’t terrible, but it’s a pretty noisy way to handle common loop conditions.

The use of where/while isn’t about eliminating either of these alternatives, they’re absolutely useful in cases where their drawbacks become advantages. For example the inline guards are great when the conditions are more complex, and necessary if you want to do more than the simple cases allow. The second form is best when you need more than the two methods, alternate methods, or you have predicates you can pass in directly, although personally when I do this I tend to do the chinning on its own lines outside of the loop, leaving me with a loop of: for eachValue in theFilteredValues { … } or whatever.

Closures are--I'm sure you'd agree--a far more advanced concept than loops. Concepts like closing over a variable are very, very hard. Many useful things can be written without using closures. Not so many things could do without loops. It very much matters that a learner might feel that he or she cannot understand everything about a loop with the handwavy explanation that it'll "come later”.

Not my point at all; my point was about the shorthand for closures not closure as a whole, you can’t learn the closure shorthands without first learning what a closure is. In exactly the same way where/while are just be shorthands for inline if/guard, you don’t need to learn about these clauses to make a functioning loop if you know how to do it with your if/guard statements. In fact it’s better to learn it in this order as once you know what each clause is a shorthand form of (if/guard continue or break) then you know exactly what it does already.

Ignoring for a moment that you’re opposed to the where clause in general, what would your thoughts be on only permitting one of where/while in a for? i.e- you would be able to do only one of:

  for eachValue in theValues where eachValue % 2 == 0 { … }
  for eachValue in theValues while eachValue < 100 { … }

But not have both a where and a while on the same line. This eliminates the question mark around the order they are applied in, while still giving us the ability to essentially switch the behaviour of the where from continue to break. I’m not decided whether I want both in a single statement or if I just want to be able to choose between them. It also limits how much goes on one line as you have to use an inline condition to achieve both for a single loop.

···

On 8 Jun 2016, at 17:11, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Wed, Jun 8, 2016 at 3:38 AM, Haravikk <swift-evolution@haravikk.me <mailto:swift-evolution@haravikk.me>> wrote:

I support your position on the use of where and while/when being confusing
in the loop statement. I (and I know others) have for example used where in
a loop statement mistakenly thinking it would terminate the loop early but
of course learned that it basically filters what causes the loop body to be
executed. After the fact that made sense to me but it didn't click at first.

If you separate the loop statement (what you are looping over) from the
filter (continue) conditions and/or termination conditions (break, guard) I
also feel it can be clearer to eyeball quickly. Additionally it lends
itself to being debugged in a line based debugger.

-Shawn

···

On Wed, Jun 8, 2016 at 9:11 AM Xiaodi Wu via swift-evolution < swift-evolution@swift.org> wrote:

On Wed, Jun 8, 2016 at 3:38 AM, Haravikk <swift-evolution@haravikk.me> > wrote:

On 8 Jun 2016, at 01:54, Xiaodi Wu via swift-evolution < >> swift-evolution@swift.org> wrote:

1) It is spelled out exactly what happens when a condition is met. I no
longer have to remember whether the word that describes breaking from a
loop uses a place analogy ("where") or a time analogy ("while" or "when”).

(You cannot convince me that these words are intuitive when the meaning
of "where" changes by context in today's Swift. Now, if you want to propose
that these be named "breakif" and "continueif" instead, then I'd agree with
you that they're intuitive names, but then they'd also be really ugly.)

I’m not sure I agree that this is confusing,

Why would breaking from a loop intuitively use a place analogy and
continuing to the next iteration use a time analogy? This is totally made
up; hence, it is not intuitive. I make no argument about whether or not it
would be conceptually confusing. If you renamed 'break' to 'foo' and
'continue' to 'bar', it would not be intuitive, but you could likewise
argue that it's not confusing, in that 'foo' is clearly not 'bar'.

a little extra to learn for new programmers perhaps but I think it’s
fairly intuitive:

while let value = foo.next() where someCondition(value) { … }

This reads to me as “repeat the following block until this fails to be
true”, the conditional binding in this case fails to be true if
someCondition(value) isn’t true, so the loop ends. I think the key thing
here is that the where clause is for the conditional binding and not the
loop itself, so in this respect it behaves exactly like an if or guard
statement. Meanwhile:

for eachValue in theValues where someCondition(eachValue) { … }

Reads as “for everything in theValues do the following if
someCondition(eachValue) is also true”, in other words this loop always
tries to visit every element of the sequence (a while loop has no implicit
awareness of the sequence, it’s really just an if statement that runs over
and over). In this case the where clause is part of the loop itself. There
may be an argument that where should be renamed on for loops to better
distinguish this, but once you consider that there’s no pattern or
conditional binding here I think it makes a reasonable amount of sense.

Yes this could be handled by an if/guard statement with continue, and
while as proposed here could be done with the same plus a break, but these
things come up so often that it just makes a lot of sense to get it all
neatly onto one line.

As I pointed out above with Tim's example, putting it all on one line is
absolutely not 'neat'--it reads like spaghetti. That is one major beef I
have with this proposal: that it *encourages* writing on one line too many
things that, whether you use `where` or not, are much more clearly written
on multiple lines. If writing everything on one line is for you the major
advantage of this proposal, we could agree on everything else and I would
be very much opposed to this proposal on that basis alone.

Chaining methods can do this, but it’s actually less readable IMO, or
requires multiple lines to keep it clear which defeats the point.

For me, encouraging the use of multiple lines is the point. Tim's example
demonstrated to me very clearly that clarity is not served by additional
sugar to reduce the amount of punctuation on one line; it is served only by
putting things on multiple lines. As I said above, I would cringe to read a
loop that begins `for foo in bar where something while somethingElse where
yetAnotherSomething while againAnotherSomething { ... }`.

As with where on if/guard statements it’s about keeping the simpler, more
common cases as clean and readable as possible. If the re-use of the
keyword where on the for loop is confusing then that’s an argument for
renaming that, rather than rejecting while or ditching the whole thing IMO.
Personally I think it’s okay, you just have to think what the where clause
is actually acting upon.

3) I have the flexibility to do something between the first if statement
and the second if statement, if I want. By placing the break statement at
the end of my loop, I could effectively choose to have one more iteration
than if I placed it at the beginning of my loop. There is nothing you can
do to mimic that choice with your proposed while clause, unless you want to
also propose a `for...in...repeat { } while` syntax.

So? Like where clauses this is for the simpler cases, if you want to do
something more complex you remain free to use more complex conditionals.

And I was/am a proponent of SE-0099 to remove `where` from if and while
loops; and if that succeeds I will definitely solicit comments to remove it
from for loops!

A lot of the time you don’t need this however, so it makes sense to
simplify the common case while leaving the complex one just as useful as it
is today. Nothing about this proposal would stop you from using if/guard
conditions inside the loop.

4) This is the perhaps the important point. A beginning programmer--not
any of us, presumably, but we were all beginners once--can accomplish
everything that he or she desires without learning this new proposed
syntax. Almost all texts, I believe, teach if statements before loops, and
teach break and continue in the same breath as the loops themselves.

In terms of teaching there shouldn’t be a problem with just teaching the
basic building blocks first, then showing off simplifications later. As
with any coding the most important thing is to get the intended behaviour
correct, simplifying or optimising the code can always come later.

You could argue the same thing about the shorthands around closures; I’m
not sure why but I had trouble with those initially until after I’d worked
with them in the more verbose form (with fully named parameters and a
return statement) till I started to get the logic behind it, now I can just
right a quick closure with the dollar sign shorthand.

Closures are--I'm sure you'd agree--a far more advanced concept than
loops. Concepts like closing over a variable are very, very hard. Many
useful things can be written without using closures. Not so many things
could do without loops. It very much matters that a learner might feel that
he or she cannot understand everything about a loop with the handwavy
explanation that it'll "come later". One critique of using Java as a
starting language is that you are forced to teach your students on day one
that the real meaning of the words "public static void main(String args)"
will "come later".

A good linter could be written to detect the presence of a simple
if/guard right inside the loop and could then suggest the use of
where/while as appropriate.

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

That's a good insight, Brent. That placement of where is actually pretty
ingenious and probably unambiguous.

···

On Wed, Jun 8, 2016 at 22:23 Brent Royal-Gordon <brent@architechies.com> wrote:

> This reads to me as “repeat the following block until this fails to be
true”, the conditional binding in this case fails to be true if
someCondition(value) isn’t true, so the loop ends. I think the key thing
here is that the where clause is for the conditional binding and not the
loop itself, so in this respect it behaves exactly like an if or guard
statement. Meanwhile:
>
> for eachValue in theValues where someCondition(eachValue) { … }
>
> Reads as “for everything in theValues do the following if
someCondition(eachValue) is also true”, in other words this loop always
tries to visit every element of the sequence (a while loop has no implicit
awareness of the sequence, it’s really just an if statement that runs over
and over). In this case the where clause is part of the loop itself. There
may be an argument that where should be renamed on for loops to better
distinguish this, but once you consider that there’s no pattern or
conditional binding here I think it makes a reasonable amount of sense.

The original sin here was in connecting the `where` clause to the for
loop's sequence expression, rather than its pattern. If `where` were
positioned right after the loop variable:

        for eachValue where someCondition(eachValue) in theValues { … }

It would be much clearer that `where` constrains the values seen by the
loop body.

I'm not sure why the `where` clause was placed where it is. I suspect it
has something to do with the `where` clause potentially being more complex
than the sequence expression, but I was not in the room where it happened,
so that's idle speculation.

--
Brent Royal-Gordon
Architechies

I still think `where` should probably be removed from for loops for the reasons
I lay out in the other thread (just use guards, lower confusion, increase readability),
but you're right. There's something wrong in the way that patterns work outside
switch statements.

Switch statement grammar:
case_item_list : pattern where_clause? | pattern where_clause? ',' case_item_list
(with inferred initializer at the end)

vs

Case condition grammar:
case_condition : 'case' pattern initializer where_clause?
(with the initializer before the where clause)

To match, the case_condition should have been:

case_condition : 'case' pattern where_clause? initializer

If SE-0099 is re-evaluated, and I have a strong sense there's a quorum of folk who want
their `where` clauses, this would introduce more consistent use across the language.

I plan to stay out of the "oh where oh where can my where clause be" argument.
I did want to throw in my observations about the inconsistencies between the
grammars. Kudos, Brent for spotting that.

-- E

···

On Jun 8, 2016, at 9:23 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:
The original sin here was in connecting the `where` clause to the for loop's sequence expression, rather than its pattern. If `where` were positioned right after the loop variable:

  for eachValue where someCondition(eachValue) in theValues { … }

It would be much clearer that `where` constrains the values seen by the loop body.

I'm not sure why the `where` clause was placed where it is. I suspect it has something to do with the `where` clause potentially being more complex than the sequence expression, but I was not in the room where it happened, so that's idle speculation.

Gist: where.md · GitHub

Regularizing Where grammar

Proposal: TBD
Author: Brent Royal-Gordon <https://github.com/brentdax&gt;, Erica Sadun <http://github.com/erica&gt;
Status: TBD
Review manager: TBD
<where.md · GitHub

This proposal fixes an inconsistency for where clause grammar in Swift language for-in loops.

Swift Evolution Discussion: Add a while clause to for loops <http://thread.gmane.org/gmane.comp.lang.swift.evolution/19772/focus=20143&gt;
<where.md · GitHub

Unlike in switch statements and do loops, a for-in loop's where-clause is separated from the pattern it modifies.

for case? pattern in expression where-clause? code-block

case-item-list → pattern where-clause? | pattern where-clause? , case-item-list

catch pattern? where-clause? code-block
This separation makes the clause harder to associate with the pattern, can confuse users as to whether it modifies the expression or the pattern, and represents an inconsistency in Swift's grammar. This proposal regularizes the grammar to match other uses.

Note where clauses in case conditions and optional bindings have been removed in SE-0099 <https://github.com/apple/swift-evolution/blob/master/proposals/0099-conditionclauses.md&gt;\.

<where.md · GitHub Design

Current:

for case? pattern in expression where-clause? code-block
Proposed:

for case? pattern where-clause? in expression code-block
<where.md · GitHub on Existing Code

Migration should be easily addressed with a simple fix-it.

<where.md · GitHub Considered

Not accepting this proposal

···

On Jun 8, 2016, at 9:23 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

This reads to me as “repeat the following block until this fails to be true”, the conditional binding in this case fails to be true if someCondition(value) isn’t true, so the loop ends. I think the key thing here is that the where clause is for the conditional binding and not the loop itself, so in this respect it behaves exactly like an if or guard statement. Meanwhile:

  for eachValue in theValues where someCondition(eachValue) { … }

Reads as “for everything in theValues do the following if someCondition(eachValue) is also true”, in other words this loop always tries to visit every element of the sequence (a while loop has no implicit awareness of the sequence, it’s really just an if statement that runs over and over). In this case the where clause is part of the loop itself. There may be an argument that where should be renamed on for loops to better distinguish this, but once you consider that there’s no pattern or conditional binding here I think it makes a reasonable amount of sense.

The original sin here was in connecting the `where` clause to the for loop's sequence expression, rather than its pattern. If `where` were positioned right after the loop variable:

  for eachValue where someCondition(eachValue) in theValues { … }

It would be much clearer that `where` constrains the values seen by the loop body.

I'm not sure why the `where` clause was placed where it is. I suspect it has something to do with the `where` clause potentially being more complex than the sequence expression, but I was not in the room where it happened, so that's idle speculation.

--
Brent Royal-Gordon
Architechies

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

> Why would breaking from a loop intuitively use a place analogy and
continuing to the next iteration use a time analogy? This is totally made
up; hence, it is not intuitive. I make no argument about whether or not it
would be conceptually confusing. If you renamed 'break' to 'foo' and
'continue' to 'bar', it would not be intuitive, but you could likewise
argue that it's not confusing, in that 'foo' is clearly not 'bar’.

I think it’s quite intuitive, just like how a standard while loop is
intuitive. “Execute this loop while this condition holds, for every case
where that condition holds.” That’s how I would phrase such an expression
in normal English. Doesn’t that make it intuitive? I can’t really switch
the meanings of “while” and “where” and still have that sentence make sense.

That is not how your proposed construct reads. It actually reads: "for
every case where that condition holds while this condition holds." That is
a terrible sentence and not "normal" English.

As I pointed out above with Tim's example, putting it all on one line is
absolutely not 'neat'--it reads like spaghetti. That is one major beef I
have with this proposal: that it *encourages* writing on one line too many
things that, whether you use `where` or not, are much more clearly written
on multiple lines. If writing everything on one line is for you the major
advantage of this proposal, we could agree on everything else and I would
be very much opposed to this proposal on that basis alone.

You could argue that this proposal encourages writing a lot on a single
line, but I could argue that not implementing this proposal would encourage
people to write stuff like

for number in fibonacci.lazy.filter({ number % 2 == 0 }).prefix(where: {
$0 < 4_000_000 }) { }

I would choose `for number in fibonacci where number % 2 == 0 while number
< 4_000_000 { }` over the statement above any day. You can break up either
into multiple lines for better readability, or you can move the conditions
inside the loop, but that’s true no matter if this proposal will be
accepted or rejected.

I'm writing in response to Haravikk's claim that method chaining encourages
putting things on multiple lines, while the proposed sugar encourages
putting things on one line. *If* you accept this premise, then I would
argue that it alone would be sufficient for me to be against the proposal.
It sounds like you don't agree with the premise, which is fine.

···

On Wed, Jun 8, 2016 at 1:24 PM, Tim Vermeulen <tvermeulen@me.com> wrote:

> On Wed, Jun 8, 2016 at 3:38 AM, Haravikk<swift-evolution@haravikk.me > (mailto:swift-evolution@haravikk.me)>wrote:
> >
> > > On 8 Jun 2016, at 01:54, Xiaodi Wu via swift-evolution< > swift-evolution@swift.org(mailto:swift-evolution@swift.org)>wrote:
> > >
> > > 1) It is spelled out exactly what happens when a condition is met. I
no longer have to remember whether the word that describes breaking from a
loop uses a place analogy ("where") or a time analogy ("while" or "when”).
> > >
> > > (You cannot convince me that these words are intuitive when the
meaning of "where" changes by context in today's Swift. Now, if you want to
propose that these be named "breakif" and "continueif" instead, then I'd
agree with you that they're intuitive names, but then they'd also be really
ugly.)
> > I’m not sure I agree that this is confusing,
> Why would breaking from a loop intuitively use a place analogy and
continuing to the next iteration use a time analogy? This is totally made
up; hence, it is not intuitive. I make no argument about whether or not it
would be conceptually confusing. If you renamed 'break' to 'foo' and
'continue' to 'bar', it would not be intuitive, but you could likewise
argue that it's not confusing, in that 'foo' is clearly not 'bar'.
>
> > a little extra to learn for new programmers perhaps but I think it’s
fairly intuitive:
> >
> > while let value = foo.next() where someCondition(value) { … }
> >
> > This reads to me as “repeat the following block until this fails to be
true”, the conditional binding in this case fails to be true if
someCondition(value) isn’t true, so the loop ends. I think the key thing
here is that the where clause is for the conditional binding and not the
loop itself, so in this respect it behaves exactly like an if or guard
statement. Meanwhile:
> >
> > for eachValue in theValues where someCondition(eachValue) { … }
> >
> > Reads as “for everything in theValues do the following if
someCondition(eachValue) is also true”, in other words this loop always
tries to visit every element of the sequence (a while loop has no implicit
awareness of the sequence, it’s really just an if statement that runs over
and over). In this case the where clause is part of the loop itself. There
may be an argument that where should be renamed on for loops to better
distinguish this, but once you consider that there’s no pattern or
conditional binding here I think it makes a reasonable amount of sense.
> >
> > Yes this could be handled by an if/guard statement with continue, and
while as proposed here could be done with the same plus a break, but these
things come up so often that it just makes a lot of sense to get it all
neatly onto one line.
> As I pointed out above with Tim's example, putting it all on one line is
absolutely not 'neat'--it reads like spaghetti. That is one major beef I
have with this proposal: that it *encourages* writing on one line too many
things that, whether you use `where` or not, are much more clearly written
on multiple lines. If writing everything on one line is for you the major
advantage of this proposal, we could agree on everything else and I would
be very much opposed to this proposal on that basis alone.
>
> > Chaining methods can do this, but it’s actually less readable IMO, or
requires multiple lines to keep it clear which defeats the point.
> >
> >
> For me, encouraging the use of multiple lines is the point. Tim's
example demonstrated to me very clearly that clarity is not served by
additional sugar to reduce the amount of punctuation on one line; it is
served only by putting things on multiple lines. As I said above, I would
cringe to read a loop that begins `for foo in bar where something while
somethingElse where yetAnotherSomething while againAnotherSomething { ...
}`.
>
> > As with where on if/guard statements it’s about keeping the simpler,
more common cases as clean and readable as possible. If the re-use of the
keyword where on the for loop is confusing then that’s an argument for
renaming that, rather than rejecting while or ditching the whole thing IMO.
Personally I think it’s okay, you just have to think what the where clause
is actually acting upon.
> >
> > > 3) I have the flexibility to do something between the first if
statement and the second if statement, if I want. By placing the break
statement at the end of my loop, I could effectively choose to have one
more iteration than if I placed it at the beginning of my loop. There is
nothing you can do to mimic that choice with your proposed while clause,
unless you want to also propose a `for...in...repeat { } while` syntax.
> >
> > So? Like where clauses this is for the simpler cases, if you want to
do something more complex you remain free to use more complex conditionals.
> And I was/am a proponent of SE-0099 to remove `where` from if and while
loops; and if that succeeds I will definitely solicit comments to remove it
from for loops!
>
> > A lot of the time you don’t need this however, so it makes sense to
simplify the common case while leaving the complex one just as useful as it
is today. Nothing about this proposal would stop you from using if/guard
conditions inside the loop.
> >
> > > 4) This is the perhaps the important point. A beginning
programmer--not any of us, presumably, but we were all beginners once--can
accomplish everything that he or she desires without learning this new
proposed syntax. Almost all texts, I believe, teach if statements before
loops, and teach break and continue in the same breath as the loops
themselves.
> > In terms of teaching there shouldn’t be a problem with just teaching
the basic building blocks first, then showing off simplifications later. As
with any coding the most important thing is to get the intended behaviour
correct, simplifying or optimising the code can always come later.
> >
> > You could argue the same thing about the shorthands around closures;
I’m not sure why but I had trouble with those initially until after I’d
worked with them in the more verbose form (with fully named parameters and
a return statement) till I started to get the logic behind it, now I can
just right a quick closure with the dollar sign shorthand.
> Closures are--I'm sure you'd agree--a far more advanced concept than
loops. Concepts like closing over a variable are very, very hard. Many
useful things can be written without using closures. Not so many things
could do without loops. It very much matters that a learner might feel that
he or she cannot understand everything about a loop with the handwavy
explanation that it'll "come later". One critique of using Java as a
starting language is that you are forced to teach your students on day one
that the real meaning of the words "public static void main(String args)"
will "come later".
>
> >
> > A good linter could be written to detect the presence of a simple
if/guard right inside the loop and could then suggest the use of
where/while as appropriate.
>
>
>

There might be value in entertaining the idea of unifying constructs such that they all allow arbitrary combinations of for/while/where/etc.

Such as:

while !stopped for unit in workToDo where unit.passesTest(condition) { unit.process() }

Which would mean something different than:

for unit in workToDo while !stopped where unit.passesTest(condition) { unit.process() }

And yes, they are very similar visually but differ subtly in meaning, but the same can be said about different sentences in english that might all share the same words and differ only by their order. It’s not exactly a foreign concept! I don’t know of any languages that are quite so expressive as that might be. Are there advantages to something more outlandish like this? I don’t know. I’m not proposing it directly, just thinking out loud, I guess.

l8r
Sean

···

On Jun 8, 2016, at 4:44 PM, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

On 8 Jun 2016, at 17:11, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Wed, Jun 8, 2016 at 3:38 AM, Haravikk <swift-evolution@haravikk.me> wrote:
Yes this could be handled by an if/guard statement with continue, and while as proposed here could be done with the same plus a break, but these things come up so often that it just makes a lot of sense to get it all neatly onto one line.

As I pointed out above with Tim's example, putting it all on one line is absolutely not 'neat'--it reads like spaghetti. That is one major beef I have with this proposal: that it *encourages* writing on one line too many things that, whether you use `where` or not, are much more clearly written on multiple lines. If writing everything on one line is for you the major advantage of this proposal, we could agree on everything else and I would be very much opposed to this proposal on that basis alone.

I’m not proposing that every single loop have all of its conditions crushed onto one line, just like I wasn’t when discussing where on the condition clause thread. The usefulness of where and the proposed while is in the common, simple cases, for example:

  for eachValue in theValues while eachValue < 100 where eachValue % 2 == 0 { … }

The alternatives would be:

  for eachValue in theValues {
    guard eachValue < 100 else { break }
    guard eachValue % 2 == 0 else { continue }
    …
  }
  for eachValue in theValues.prefix(while: { $0 < 100 }).filter({ $0 % 2 == 0 }) { … } // Could also be on multiple lines

The former wastes vertical space for what it does IMO; it’s fine if the conditions were more complicated, but since they’re not where/while is ideal. The second isn’t terrible, but it’s a pretty noisy way to handle common loop conditions.

The use of where/while isn’t about eliminating either of these alternatives, they’re absolutely useful in cases where their drawbacks become advantages. For example the inline guards are great when the conditions are more complex, and necessary if you want to do more than the simple cases allow. The second form is best when you need more than the two methods, alternate methods, or you have predicates you can pass in directly, although personally when I do this I tend to do the chinning on its own lines outside of the loop, leaving me with a loop of: for eachValue in theFilteredValues { … } or whatever.

Closures are--I'm sure you'd agree--a far more advanced concept than loops. Concepts like closing over a variable are very, very hard. Many useful things can be written without using closures. Not so many things could do without loops. It very much matters that a learner might feel that he or she cannot understand everything about a loop with the handwavy explanation that it'll "come later”.

Not my point at all; my point was about the shorthand for closures not closure as a whole, you can’t learn the closure shorthands without first learning what a closure is. In exactly the same way where/while are just be shorthands for inline if/guard, you don’t need to learn about these clauses to make a functioning loop if you know how to do it with your if/guard statements. In fact it’s better to learn it in this order as once you know what each clause is a shorthand form of (if/guard continue or break) then you know exactly what it does already.

Ignoring for a moment that you’re opposed to the where clause in general, what would your thoughts be on only permitting one of where/while in a for? i.e- you would be able to do only one of:

  for eachValue in theValues where eachValue % 2 == 0 { … }
  for eachValue in theValues while eachValue < 100 { … }

But not have both a where and a while on the same line. This eliminates the question mark around the order they are applied in, while still giving us the ability to essentially switch the behaviour of the where from continue to break. I’m not decided whether I want both in a single statement or if I just want to be able to choose between them. It also limits how much goes on one line as you have to use an inline condition to achieve both for a single loop.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Yes this could be handled by an if/guard statement with continue, and

while as proposed here could be done with the same plus a break, but these
things come up so often that it just makes a lot of sense to get it all
neatly onto one line.

As I pointed out above with Tim's example, putting it all on one line is
absolutely not 'neat'--it reads like spaghetti. That is one major beef I
have with this proposal: that it *encourages* writing on one line too many
things that, whether you use `where` or not, are much more clearly written
on multiple lines. If writing everything on one line is for you the major
advantage of this proposal, we could agree on everything else and I would
be very much opposed to this proposal on that basis alone.

I’m not proposing that every single loop have all of its conditions
crushed onto one line, just like I wasn’t when discussing where on the
condition clause thread. The usefulness of where and the proposed while is
in the common, simple cases, for example:

for eachValue in theValues while eachValue < 100 where eachValue % 2 == 0
{ … }

The alternatives would be:

for eachValue in theValues {
guard eachValue < 100 else { break }
guard eachValue % 2 == 0 else { continue }

}
for eachValue in theValues.prefix(while: { $0 < 100 }).filter({ $0 % 2 ==
0 }) { … } // Could also be on multiple lines

The former wastes vertical space for what it does IMO; it’s fine if the
conditions were more complicated, but since they’re not where/while is
ideal. The second isn’t terrible, but it’s a pretty noisy way to handle
common loop conditions.

We've rehashed this a few times. The version with guard statements is what
I argue is the ideal. Perhaps you can prove me wrong, but I have never
heard anyone enunciate a principle regarding conservation of vertical
space. Line length, however, there's been tomes written about that.

The last version is unreadable to me, because it's too long; the first
version with your proposed syntax suffers the same defect, but has fewer
punctuation marks.

The use of where/while isn’t about eliminating either of these
alternatives, they’re absolutely useful in cases where their drawbacks
become advantages. For example the inline guards are great when the
conditions are more complex, and necessary if you want to do more than the
simple cases allow. The second form is best when you need more than the two
methods, alternate methods, or you have predicates you can pass in
directly, although personally when I do this I tend to do the chinning on
its own lines outside of the loop, leaving me with a loop of: for eachValue
in theFilteredValues { … } or whatever.

Yes, that's a good option as well IMO.

Closures are--I'm sure you'd agree--a far more advanced concept than
loops. Concepts like closing over a variable are very, very hard. Many
useful things can be written without using closures. Not so many things
could do without loops. It very much matters that a learner might feel that
he or she cannot understand everything about a loop with the handwavy
explanation that it'll "come later”.

Not my point at all; my point was about the shorthand for closures not
closure as a whole, you can’t learn the closure shorthands without first
learning what a closure is.

Neither here nor there, but what you call a "closure shorthand" is a
shorthand for functions in general; you can absolutely write something in
that shorthand that doesn't close over anything in the outer scope (making
it, by definition, not a closure). And it is definitely possible, with
trailing closure syntax, to write a closure without learning what it is.
Consider, for example, the future `queue.async { ... }`.

In exactly the same way where/while are just be shorthands for inline
if/guard, you don’t need to learn about these clauses to make a functioning
loop if you know how to do it with your if/guard statements. In fact it’s
better to learn it in this order as once you know what each clause is a
shorthand form of (if/guard continue or break) then you know exactly what
it does already.

Learning to code involves not just learning what you'll use but also
understanding other people's code when you read it. As I mentioned above, I
have seen a student helpless with frustration because he could not
understand what the ++ operator does (in his case, in Java). More
accurately, he understood the fact that it's a shorthand and what it's a
shorthand for, but he could not see a rationale for its existence and
concluded that he must be misunderstanding some major concept regarding
operators in general. It was a huge stumbling block, not because he was
incapable of learning this syntax but because the syntax seemed
unnecessarily redundant and illogical. "There must be something else going
on," he insisted over and over.

Ignoring for a moment that you’re opposed to the where clause in general,
what would your thoughts be on only permitting one of where/while in a for?
i.e- you would be able to do only one of:

for eachValue in theValues where eachValue % 2 == 0 { … }
for eachValue in theValues while eachValue < 100 { … }

But not have both a where and a while on the same line. This eliminates
the question mark around the order they are applied in, while still giving
us the ability to essentially switch the behaviour of the where from
continue to break. I’m not decided whether I want both in a single
statement or if I just want to be able to choose between them. It also
limits how much goes on one line as you have to use an inline condition to
achieve both for a single loop.

I could live with that, although maybe I would want to explore different
words, as they do look very similar visually. I think this will also
depend, as Erica says, on the outcome of SE-0099.

···

On Wed, Jun 8, 2016 at 4:44 PM, Haravikk <swift-evolution@haravikk.me> wrote:

On 8 Jun 2016, at 17:11, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
On Wed, Jun 8, 2016 at 3:38 AM, Haravikk <swift-evolution@haravikk.me> > wrote:

Well put; an excellent articulation of concerns arising from the daily
experience of using the feature.

···

On Wed, Jun 8, 2016 at 19:14 Shawn Erickson <shawnce@gmail.com> wrote:

I support your position on the use of where and while/when being confusing
in the loop statement. I (and I know others) have for example used where in
a loop statement mistakenly thinking it would terminate the loop early but
of course learned that it basically filters what causes the loop body to be
executed. After the fact that made sense to me but it didn't click at first.

If you separate the loop statement (what you are looping over) from the
filter (continue) conditions and/or termination conditions (break, guard) I
also feel it can be clearer to eyeball quickly. Additionally it lends
itself to being debugged in a line based debugger.

-Shawn
On Wed, Jun 8, 2016 at 9:11 AM Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote:

On Wed, Jun 8, 2016 at 3:38 AM, Haravikk <swift-evolution@haravikk.me> >> wrote:

On 8 Jun 2016, at 01:54, Xiaodi Wu via swift-evolution < >>> swift-evolution@swift.org> wrote:

1) It is spelled out exactly what happens when a condition is met. I no
longer have to remember whether the word that describes breaking from a
loop uses a place analogy ("where") or a time analogy ("while" or "when”).

(You cannot convince me that these words are intuitive when the meaning
of "where" changes by context in today's Swift. Now, if you want to propose
that these be named "breakif" and "continueif" instead, then I'd agree with
you that they're intuitive names, but then they'd also be really ugly.)

I’m not sure I agree that this is confusing,

Why would breaking from a loop intuitively use a place analogy and
continuing to the next iteration use a time analogy? This is totally made
up; hence, it is not intuitive. I make no argument about whether or not it
would be conceptually confusing. If you renamed 'break' to 'foo' and
'continue' to 'bar', it would not be intuitive, but you could likewise
argue that it's not confusing, in that 'foo' is clearly not 'bar'.

a little extra to learn for new programmers perhaps but I think it’s
fairly intuitive:

while let value = foo.next() where someCondition(value) { … }

This reads to me as “repeat the following block until this fails to be
true”, the conditional binding in this case fails to be true if
someCondition(value) isn’t true, so the loop ends. I think the key thing
here is that the where clause is for the conditional binding and not the
loop itself, so in this respect it behaves exactly like an if or guard
statement. Meanwhile:

for eachValue in theValues where someCondition(eachValue) { … }

Reads as “for everything in theValues do the following if
someCondition(eachValue) is also true”, in other words this loop always
tries to visit every element of the sequence (a while loop has no implicit
awareness of the sequence, it’s really just an if statement that runs over
and over). In this case the where clause is part of the loop itself. There
may be an argument that where should be renamed on for loops to better
distinguish this, but once you consider that there’s no pattern or
conditional binding here I think it makes a reasonable amount of sense.

Yes this could be handled by an if/guard statement with continue, and
while as proposed here could be done with the same plus a break, but these
things come up so often that it just makes a lot of sense to get it all
neatly onto one line.

As I pointed out above with Tim's example, putting it all on one line is
absolutely not 'neat'--it reads like spaghetti. That is one major beef I
have with this proposal: that it *encourages* writing on one line too many
things that, whether you use `where` or not, are much more clearly written
on multiple lines. If writing everything on one line is for you the major
advantage of this proposal, we could agree on everything else and I would
be very much opposed to this proposal on that basis alone.

Chaining methods can do this, but it’s actually less readable IMO, or
requires multiple lines to keep it clear which defeats the point.

For me, encouraging the use of multiple lines is the point. Tim's example
demonstrated to me very clearly that clarity is not served by additional
sugar to reduce the amount of punctuation on one line; it is served only by
putting things on multiple lines. As I said above, I would cringe to read a
loop that begins `for foo in bar where something while somethingElse where
yetAnotherSomething while againAnotherSomething { ... }`.

As with where on if/guard statements it’s about keeping the simpler,
more common cases as clean and readable as possible. If the re-use of the
keyword where on the for loop is confusing then that’s an argument for
renaming that, rather than rejecting while or ditching the whole thing IMO.
Personally I think it’s okay, you just have to think what the where clause
is actually acting upon.

3) I have the flexibility to do something between the first if statement
and the second if statement, if I want. By placing the break statement at
the end of my loop, I could effectively choose to have one more iteration
than if I placed it at the beginning of my loop. There is nothing you can
do to mimic that choice with your proposed while clause, unless you want to
also propose a `for...in...repeat { } while` syntax.

So? Like where clauses this is for the simpler cases, if you want to do
something more complex you remain free to use more complex conditionals.

And I was/am a proponent of SE-0099 to remove `where` from if and while
loops; and if that succeeds I will definitely solicit comments to remove it
from for loops!

A lot of the time you don’t need this however, so it makes sense to
simplify the common case while leaving the complex one just as useful as it
is today. Nothing about this proposal would stop you from using if/guard
conditions inside the loop.

4) This is the perhaps the important point. A beginning programmer--not
any of us, presumably, but we were all beginners once--can accomplish
everything that he or she desires without learning this new proposed
syntax. Almost all texts, I believe, teach if statements before loops, and
teach break and continue in the same breath as the loops themselves.

In terms of teaching there shouldn’t be a problem with just teaching the
basic building blocks first, then showing off simplifications later. As
with any coding the most important thing is to get the intended behaviour
correct, simplifying or optimising the code can always come later.

You could argue the same thing about the shorthands around closures; I’m
not sure why but I had trouble with those initially until after I’d worked
with them in the more verbose form (with fully named parameters and a
return statement) till I started to get the logic behind it, now I can just
right a quick closure with the dollar sign shorthand.

Closures are--I'm sure you'd agree--a far more advanced concept than
loops. Concepts like closing over a variable are very, very hard. Many
useful things can be written without using closures. Not so many things
could do without loops. It very much matters that a learner might feel that
he or she cannot understand everything about a loop with the handwavy
explanation that it'll "come later". One critique of using Java as a
starting language is that you are forced to teach your students on day one
that the real meaning of the words "public static void main(String args)"
will "come later".

A good linter could be written to detect the presence of a simple
if/guard right inside the loop and could then suggest the use of
where/while as appropriate.

_______________________________________________

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

Since Swift strives to be an opinionated language without dialects, there shouldn't be more "choice" but rather one general solution, IMO.

I agree with you on this in general, but this proposal isn’t just about adding choices to the language. At least, that’s not the point. It doesn’t add any new functionality per se, but there might be value in making a common coding pattern more shorter and more intuitive. `guard` is a lot more powerful than `where` or `while` as discussed here, but such clauses can possibly make code more readable. You don’t have to agree with me that those clauses are actually more readable than using `guard`, but that’s the way I see it and in my opinion it’s about more than just having more options.

In fact, if this proposal is accepted, one could consider `guard someCondition else { continue/break }` at the start of a for loop to be a code smell because a `where`/`while` clause could have been used instead. So using those clauses would then be the general solution to the problem, which is in line with what you said Swift strives to be.

To me this issue feels similar to adding `guard` despite already having `if` (if we disregard `guard let` for a second). Now you can write both `guard someCondition else { return }` and `if !someCondition { return }`, but I would consider the first one the general solution and the second one code smell. This pattern is so common that adding `guard` was justified.

···

On Wed, Jun 8, 2016 at 1:58 PM, Tim Vermeulen<tvermeulen@me.com(mailto:tvermeulen@me.com)>wrote:
> That’s why I said “potentially less elegant”, some people might prefer `where` over `guard`. This proposal would give them the choice (in very specific situations) to use `where` rather than `guard` if they don’t want to sacrifice performance.
Since Swift strives to be an opinionated language without dialects, there shouldn't be more "choice" but rather one general solution, IMO. Since `guard` doesn't sacrifice performance and is the most general, I would oppose adding the option of `while` to offer more choice.

>
> >On Wed, Jun 8, 2016 at 1:35 PM, Tim Vermeulen via swift-evolution<swift-evolution@swift.org(mailto:swift-evolution@swift.org)(mailto:swift-evolution@swift.org)>wrote:
> >>This is a really strong argument in my opinion. If we don’t add a `while` to for loops, then in some situations we will have to rewrite a `where` clause to something potentially less elegant, given that we don’t want to give up performance.
> >I disagree. I argue that what you call "less elegant", namely if (or guard) inside the loop, is the most elegant solution.
> >
> >>
> >>>IMO `.prefix` is just not the equal alternative for as proposed `while` :
> >>>in case of 'while' expression `number<4_000_000` will be calculated
> >>>*only* for those who `number % 2 == 0`. In case of `prefix` - the
> >>>expression will be processed for each `number` and only after this filtered
> >>>by `number % 2`. Let's assume we need to check for some
> >>>veryExpensiveTest(number):
> >>>
> >>>for number in fibonacci where number % 2 == 0 while
> >>>veryExpensiveTest(number) {}
> >>>
> >>>let numbers = fibonacci.prefix { veryExpensiveTest($0) }
> >>>for number in numbers where number % 2 == 0 {}
> >>>
> >>>So, `while` for `for` loops just can't be always replaced with `prefix`
> >>>
> >>>On 08.06.2016 2:02, Xiaodi Wu via swift-evolution wrote:
> >>>>On Tue, Jun 7, 2016 at 5:11 PM, Tim Vermeulen<tvermeulen@me.com(mailto:tvermeulen@me.com)(mailto:tvermeulen@me.com) > > >>>><mailto:tvermeulen@me.com>>wrote:
> >>>>
> >>>>I’ve been thinking about this for a bit now, and I think it would make
> >>>>most sense to evaluate these clauses from left to right. However, cases
> >>>>where the order matters are very uncommon, and I would rather have the
> >>>>power to choose which clause is evaluated first than to have a forced
> >>>>default order. Either way I don’t see this as a reason not to allow
> >>>>combining the two clauses because IMO it can lead to some very clean
> >>>>code. For instance, say we want to loop through all even fibonacci
> >>>>numbers below 4 million (see problem #2 from project euler), we could
> >>>>do this:
> >>>>
> >>>>`for number in fibonacci where number % 2 == 0 while number<4_000_000
> >>>>{ }`
> >>>>
> >>>>
> >>>>This statement looks like spaghetti to me. I would not at all support
> >>>>extending the language to permit it. Do you really think it's more readable
> >>>>than going step-by-step?
> >>>>
> >>>>```
> >>>>let numbers = fibonacci.prefix { $0<4_000_000 }
> >>>>for number in numbers where number % 2 == 0 {
> >>>>// ...
> >>>>}
> >>>>```
> >>>>
> >>>>or just:
> >>>>
> >>>>```
> >>>>let numbers = fibonacci.prefix { $0<4_000_000 }
> >>>>let evens = numbers.filter { $0 % 2 == 0 }
> >>>>for number in evens {
> >>>>// ...
> >>>>}
> >>>>```
> >>>>
> >>>>
> >>>>I could have ordered the two clauses in any way I want. If combining
> >>>>the clauses weren’t allowed, I’d have to put (at least) one of them
> >>>>inside the block, which would be a (minor) pain.
> >>>>
> >>>>I don’t currently have a very strong opinion about the order of
> >>>>evaluation, so I might be convinced otherwise. But combining the two
> >>>>clauses is so powerful that I don’t think it’s worth to get rid of just
> >>>>because of an edge case.
> >>>>
> >>>>>It may be workable if you can have only one or the other, but mixing and matching them as proposed above would be a world of hurt:
> >>>>>
> >>>>>```
> >>>>>for foo in bar where condition1 while condition2 { ... }
> >>>>>```
> >>>>>
> >>>>>If condition1 and condition2 both evaluate to true, then whether you continue or break would depend on the relative order of where and while; for generality, you would want to allow both `for...in...where...while` and `for...in...while...where`, and likely `for...in...while...where...while`, etc. There is nothing in the meaning of those words that would suggest that `while...where` behaves differently from `where...while`, etc. This is why words like "break" and "continue" are IMO far superior.
> >>>>>
> >>>>>
> >>>>>On Tue, Jun 7, 2016 at 2:34 PM, Erica Sadun<erica@ericasadun.com(mailto:erica@ericasadun.com)(mailto:erica@ericasadun.com) > > >>>><mailto:erica@ericasadun.com>(mailto:erica@ericasadun.com > > >>>><mailto:erica@ericasadun.com>)>wrote:
> >>>>>>
> >>>>>>>On Jun 7, 2016, at 1:16 PM, Tim Vermeulen via swift-evolution<swift-evolution@swift.org(mailto:swift-evolution@swift.org)(mailto:swift-evolution@swift.org) > > >>>><mailto:swift-evolution@swift.org>(mailto:swift-evolution@swift.org > > >>>><mailto:swift-evolution@swift.org>)>wrote:
> >>>>>>>>The meaning of the proposed while is not at all a pair for where, since where clauses in while loops would do the same thing as while clauses in for loops. That's crazy.
> >>>>>>>
> >>>>>>>It sounds crazy, but it’s the nature of the while loop. A where clause in a while loop also has a different result than a where clause in a for loop.
> >>>>>>
> >>>>>>The where_clause appears in the for in statement
> >>>>>>
> >>>>>>for_in_statement : 'for' 'case'? pattern 'in' expression where_clause? code_block
> >>>>>>
> >>>>>>It's syntactic sugar because the expression can be already be limited through functional chaining of some sort or another. At the same time, it's nice and pleasant to have `where` and I'm not itching to throw it out. The same courtesy could be easily extend to `when` (because I don't really want to use the `while` keyword here, but I could easily be convinced otherwise because I don't have a strong stance either way):
> >>>>>>
> >>>>>>for_in_statement : 'for' 'case'? pattern 'in' expression (where_clause | when_clause)? code_block
> >>>>>>when_clause : 'when' expression
> >>>>>>
> >>>>>>and again it could be nice and pleasant to have, although not necessary. The question comes down to how much does the language benefit by this sugar.
> >>>>>>
> >>>>>>I'd say that in both cases, combining chaining and statements is
> >>>>marginallyless goodthan either using standalone chaining or statements
> >>>>without chaining. But as I say this, I know as a fact, I fully intend
> >>>>to use `sequence(_:, next:).take(while:)` with for0in statements, so
> >>>>I'm starting from a hypocritical vantage point.
> >>>>>>
> >>>>>>To summarize, I'm more +0.01 than I am -0.01 on this.
> >>>>>>
> >>>>>>-- E
> >>>>>>p.s. Sorry, wux
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>_______________________________________________
> >>>>swift-evolution mailing list
> >>>>swift-evolution@swift.org(mailto: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(mailto:swift-evolution@swift.org)(mailto:swift-evolution@swift.org)
> >>https://lists.swift.org/mailman/listinfo/swift-evolution
> >
> >
> >

It’s funny that you use this example as an argument against this proposal, because what led me to propose the `while` clause in the first place was a very similar incident (but instead of using `where` expecting it to terminate early, I tried to use a `while` clause, not immediately realising this can’t currently be done).

···

I support your position on the use of where and while/when being confusing in the loop statement. I (and I know others) have for example used where in a loop statement mistakenly thinking it would terminate the loop early but of course learned that it basically filters what causes the loop body to be executed. After the fact that made sense to me but it didn't click at first.

If you separate the loop statement (what you are looping over) from the filter (continue) conditions and/or termination conditions (break, guard) I also feel it can be clearer to eyeball quickly. Additionally it lends itself to being debugged in a line based debugger.

-Shawn
On Wed, Jun 8, 2016 at 9:11 AM Xiaodi Wu via swift-evolution<swift-evolution@swift.org(mailto:swift-evolution@swift.org)>wrote:
> On Wed, Jun 8, 2016 at 3:38 AM, Haravikk<swift-evolution@haravikk.me(mailto:swift-evolution@haravikk.me)>wrote:
> >
> > > On 8 Jun 2016, at 01:54, Xiaodi Wu via swift-evolution<swift-evolution@swift.org(mailto:swift-evolution@swift.org)>wrote:
> > >
> > > 1) It is spelled out exactly what happens when a condition is met. I no longer have to remember whether the word that describes breaking from a loop uses a place analogy ("where") or a time analogy ("while" or "when”).
> > >
> > > (You cannot convince me that these words are intuitive when the meaning of "where" changes by context in today's Swift. Now, if you want to propose that these be named "breakif" and "continueif" instead, then I'd agree with you that they're intuitive names, but then they'd also be really ugly.)
> > I’m not sure I agree that this is confusing,
>
> Why would breaking from a loop intuitively use a place analogy and continuing to the next iteration use a time analogy? This is totally made up; hence, it is not intuitive. I make no argument about whether or not it would be conceptually confusing. If you renamed 'break' to 'foo' and 'continue' to 'bar', it would not be intuitive, but you could likewise argue that it's not confusing, in that 'foo' is clearly not 'bar'.
>
> > a little extra to learn for new programmers perhaps but I think it’s fairly intuitive:
> >
> > while let value = foo.next() where someCondition(value) { … }
> >
> > This reads to me as “repeat the following block until this fails to be true”, the conditional binding in this case fails to be true if someCondition(value) isn’t true, so the loop ends. I think the key thing here is that the where clause is for the conditional binding and not the loop itself, so in this respect it behaves exactly like an if or guard statement. Meanwhile:
> >
> > for eachValue in theValues where someCondition(eachValue) { … }
> >
> > Reads as “for everything in theValues do the following if someCondition(eachValue) is also true”, in other words this loop always tries to visit every element of the sequence (a while loop has no implicit awareness of the sequence, it’s really just an if statement that runs over and over). In this case the where clause is part of the loop itself. There may be an argument that where should be renamed on for loops to better distinguish this, but once you consider that there’s no pattern or conditional binding here I think it makes a reasonable amount of sense.
> >
> > Yes this could be handled by an if/guard statement with continue, and while as proposed here could be done with the same plus a break, but these things come up so often that it just makes a lot of sense to get it all neatly onto one line.
>
> As I pointed out above with Tim's example, putting it all on one line is absolutely not 'neat'--it reads like spaghetti. That is one major beef I have with this proposal: that it *encourages* writing on one line too many things that, whether you use `where` or not, are much more clearly written on multiple lines. If writing everything on one line is for you the major advantage of this proposal, we could agree on everything else and I would be very much opposed to this proposal on that basis alone.
>
> > Chaining methods can do this, but it’s actually less readable IMO, or requires multiple lines to keep it clear which defeats the point.
> >
> >
>
>
> For me, encouraging the use of multiple lines is the point. Tim's example demonstrated to me very clearly that clarity is not served by additional sugar to reduce the amount of punctuation on one line; it is served only by putting things on multiple lines. As I said above, I would cringe to read a loop that begins `for foo in bar where something while somethingElse where yetAnotherSomething while againAnotherSomething { ... }`.
>
> > As with where on if/guard statements it’s about keeping the simpler, more common cases as clean and readable as possible. If the re-use of the keyword where on the for loop is confusing then that’s an argument for renaming that, rather than rejecting while or ditching the whole thing IMO. Personally I think it’s okay, you just have to think what the where clause is actually acting upon.
> >
> > > 3) I have the flexibility to do something between the first if statement and the second if statement, if I want. By placing the break statement at the end of my loop, I could effectively choose to have one more iteration than if I placed it at the beginning of my loop. There is nothing you can do to mimic that choice with your proposed while clause, unless you want to also propose a `for...in...repeat { } while` syntax.
> >
> > So? Like where clauses this is for the simpler cases, if you want to do something more complex you remain free to use more complex conditionals.
>
> And I was/am a proponent of SE-0099 to remove `where` from if and while loops; and if that succeeds I will definitely solicit comments to remove it from for loops!
>
> > A lot of the time you don’t need this however, so it makes sense to simplify the common case while leaving the complex one just as useful as it is today. Nothing about this proposal would stop you from using if/guard conditions inside the loop.
> >
> > > 4) This is the perhaps the important point. A beginning programmer--not any of us, presumably, but we were all beginners once--can accomplish everything that he or she desires without learning this new proposed syntax. Almost all texts, I believe, teach if statements before loops, and teach break and continue in the same breath as the loops themselves.
> > In terms of teaching there shouldn’t be a problem with just teaching the basic building blocks first, then showing off simplifications later. As with any coding the most important thing is to get the intended behaviour correct, simplifying or optimising the code can always come later.
> >
> > You could argue the same thing about the shorthands around closures; I’m not sure why but I had trouble with those initially until after I’d worked with them in the more verbose form (with fully named parameters and a return statement) till I started to get the logic behind it, now I can just right a quick closure with the dollar sign shorthand.
>
> Closures are--I'm sure you'd agree--a far more advanced concept than loops. Concepts like closing over a variable are very, very hard. Many useful things can be written without using closures. Not so many things could do without loops. It very much matters that a learner might feel that he or she cannot understand everything about a loop with the handwavy explanation that it'll "come later". One critique of using Java as a starting language is that you are forced to teach your students on day one that the real meaning of the words "public static void main(String args)" will "come later".
>
> >
> > A good linter could be written to detect the presence of a simple if/guard right inside the loop and could then suggest the use of where/while as appropriate._______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org(mailto:swift-evolution@swift.org)
> https://lists.swift.org/mailman/listinfo/swift-evolution

+1

···

On Jun 9, 2016, at 1:05 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

Gist: where.md · GitHub

Regularizing Where grammar

Proposal: TBD
Author: Brent Royal-Gordon <https://github.com/brentdax&gt;, Erica Sadun <http://github.com/erica&gt;
Status: TBD
Review manager: TBD
<where.md · GitHub

This proposal fixes an inconsistency for where clause grammar in Swift language for-in loops.

Swift Evolution Discussion: Add a while clause to for loops <http://thread.gmane.org/gmane.comp.lang.swift.evolution/19772/focus=20143&gt;
<where.md · GitHub

Unlike in switch statements and do loops, a for-in loop's where-clause is separated from the pattern it modifies.

for case? pattern in expression where-clause? code-block

case-item-list → pattern where-clause? | pattern where-clause? , case-item-list

catch pattern? where-clause? code-block
This separation makes the clause harder to associate with the pattern, can confuse users as to whether it modifies the expression or the pattern, and represents an inconsistency in Swift's grammar. This proposal regularizes the grammar to match other uses.

Note where clauses in case conditions and optional bindings have been removed in SE-0099 <https://github.com/apple/swift-evolution/blob/master/proposals/0099-conditionclauses.md&gt;\.

<where.md · GitHub Design

Current:

for case? pattern in expression where-clause? code-block
Proposed:

for case? pattern where-clause? in expression code-block
<where.md · GitHub on Existing Code

Migration should be easily addressed with a simple fix-it.

<where.md · GitHub Considered

Not accepting this proposal

On Jun 8, 2016, at 9:23 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This reads to me as “repeat the following block until this fails to be true”, the conditional binding in this case fails to be true if someCondition(value) isn’t true, so the loop ends. I think the key thing here is that the where clause is for the conditional binding and not the loop itself, so in this respect it behaves exactly like an if or guard statement. Meanwhile:

  for eachValue in theValues where someCondition(eachValue) { … }

Reads as “for everything in theValues do the following if someCondition(eachValue) is also true”, in other words this loop always tries to visit every element of the sequence (a while loop has no implicit awareness of the sequence, it’s really just an if statement that runs over and over). In this case the where clause is part of the loop itself. There may be an argument that where should be renamed on for loops to better distinguish this, but once you consider that there’s no pattern or conditional binding here I think it makes a reasonable amount of sense.

The original sin here was in connecting the `where` clause to the for loop's sequence expression, rather than its pattern. If `where` were positioned right after the loop variable:

  for eachValue where someCondition(eachValue) in theValues { … }

It would be much clearer that `where` constrains the values seen by the loop body.

I'm not sure why the `where` clause was placed where it is. I suspect it has something to do with the `where` clause potentially being more complex than the sequence expression, but I was not in the room where it happened, so that's idle speculation.

--
Brent Royal-Gordon
Architechies

_______________________________________________
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

Can you include an example? I find it hard to visualize for case? pattern where-clause? in expression code-block

Thanks,
Brandon

···

On Jun 9, 2016, at 3:05 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

Gist: where.md · GitHub

Regularizing Where grammar

Proposal: TBD
Author: Brent Royal-Gordon <https://github.com/brentdax&gt;, Erica Sadun <http://github.com/erica&gt;
Status: TBD
Review manager: TBD
<where.md · GitHub

This proposal fixes an inconsistency for where clause grammar in Swift language for-in loops.

Swift Evolution Discussion: Add a while clause to for loops <http://thread.gmane.org/gmane.comp.lang.swift.evolution/19772/focus=20143&gt;
<where.md · GitHub

Unlike in switch statements and do loops, a for-in loop's where-clause is separated from the pattern it modifies.

for case? pattern in expression where-clause? code-block

case-item-list → pattern where-clause? | pattern where-clause? , case-item-list

catch pattern? where-clause? code-block
This separation makes the clause harder to associate with the pattern, can confuse users as to whether it modifies the expression or the pattern, and represents an inconsistency in Swift's grammar. This proposal regularizes the grammar to match other uses.

Note where clauses in case conditions and optional bindings have been removed in SE-0099 <https://github.com/apple/swift-evolution/blob/master/proposals/0099-conditionclauses.md&gt;\.

<where.md · GitHub Design

Current:

for case? pattern in expression where-clause? code-block
Proposed:

for case? pattern where-clause? in expression code-block
<where.md · GitHub on Existing Code

Migration should be easily addressed with a simple fix-it.

<where.md · GitHub Considered

Not accepting this proposal

On Jun 8, 2016, at 9:23 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This reads to me as “repeat the following block until this fails to be true”, the conditional binding in this case fails to be true if someCondition(value) isn’t true, so the loop ends. I think the key thing here is that the where clause is for the conditional binding and not the loop itself, so in this respect it behaves exactly like an if or guard statement. Meanwhile:

  for eachValue in theValues where someCondition(eachValue) { … }

Reads as “for everything in theValues do the following if someCondition(eachValue) is also true”, in other words this loop always tries to visit every element of the sequence (a while loop has no implicit awareness of the sequence, it’s really just an if statement that runs over and over). In this case the where clause is part of the loop itself. There may be an argument that where should be renamed on for loops to better distinguish this, but once you consider that there’s no pattern or conditional binding here I think it makes a reasonable amount of sense.

The original sin here was in connecting the `where` clause to the for loop's sequence expression, rather than its pattern. If `where` were positioned right after the loop variable:

  for eachValue where someCondition(eachValue) in theValues { … }

It would be much clearer that `where` constrains the values seen by the loop body.

I'm not sure why the `where` clause was placed where it is. I suspect it has something to do with the `where` clause potentially being more complex than the sequence expression, but I was not in the room where it happened, so that's idle speculation.

--
Brent Royal-Gordon
Architechies

_______________________________________________
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