-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add C++-like `while` loops - Omits variable declarations in condition syntax (`while (auto x = DoSomething())`).
- Loading branch information
Showing
2 changed files
with
254 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,253 @@ | ||
# while loops | ||
|
||
<!-- | ||
Part of the Carbon Language project, under the Apache License v2.0 with LLVM | ||
Exceptions. See /LICENSE for license information. | ||
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
--> | ||
|
||
[Pull request](https://github.com/carbon-language/carbon-lang/pull/340) | ||
|
||
<!-- toc --> | ||
|
||
## Table of contents | ||
|
||
- [Problem](#problem) | ||
- [Background](#background) | ||
- [Proposal](#proposal) | ||
- [Details](#details) | ||
- [Executable semantics form](#executable-semantics-form) | ||
- [Caveats](#caveats) | ||
- [C++ as baseline](#c-as-baseline) | ||
- [`do`/`while`](#dowhile) | ||
- [Rationale based on Carbon's goals](#rationale-based-on-carbons-goals) | ||
- [Alternatives considered](#alternatives-considered) | ||
- [Non-C++ syntax](#non-c-syntax) | ||
- [Initializing variables in the `while`](#initializing-variables-in-the-while) | ||
|
||
<!-- tocstop --> | ||
|
||
## Problem | ||
|
||
`while` is noted in the [language overview](/docs/design/README.md#while), but | ||
is provisional. Control flow is important, and `while` is basic; the form is | ||
similar in many languages, even if details may change. | ||
|
||
## Background | ||
|
||
- C++: A couple example languages following C++'s syntax closely are Java and | ||
TypeScript. | ||
|
||
```cc | ||
while (x) { | ||
DoSomething(); | ||
} | ||
|
||
do { | ||
DoSomethingElse(); | ||
} while (y); | ||
``` | ||
|
||
- Python: Python does not provide `do`/`while`. However, the `else` syntax for | ||
having code execute if the condition is _never_ true may be of interest. | ||
|
||
```python | ||
while x: | ||
DoSomething() | ||
|
||
while True: | ||
DoSomethingElse() | ||
if not y: | ||
break | ||
|
||
while z: | ||
print("z is true") | ||
else: | ||
print("z was never true") | ||
``` | ||
|
||
- Swift: Swift uses `repeat` instead of `do`. | ||
|
||
```swift | ||
while x { | ||
DoSomething() | ||
} | ||
|
||
repeat { | ||
DoSomethingElse() | ||
} while y | ||
``` | ||
|
||
- Rust: Rust provides only a basic `while` loop, relying on the condition-less | ||
`loop` to achieve `do`/`while`-like behavior. | ||
|
||
```rust | ||
while x { | ||
DoSomething(); | ||
} | ||
|
||
loop { | ||
DoSomethingElse(); | ||
if (!y) { break; } | ||
} | ||
``` | ||
|
||
- Go: Go has no `while` loops, only `for` loops. However, a `for` can be | ||
written similar to a `while`. | ||
```go | ||
for x { | ||
DoSomething() | ||
} | ||
for { | ||
DoSomethingElse(); | ||
if !y { break; } | ||
} | ||
``` | ||
## Proposal | ||
Carbon should adopt `while` loop syntax consistent with C/C++. In particular, it | ||
should adopt these three kinds of statements: | ||
- `while`: declares that we're doing a loop, containing the condition. | ||
- `continue`: continues with the next loop iteration, starting with the loop | ||
condition. | ||
- `break`: breaks out of the loop, without testing the loop condition. | ||
## Details | ||
Loop syntax looks like: | ||
- `while (` _boolean expression_ `) {` _statements_ `}` | ||
While will evaluate the loop condition before each pass of the loop, only | ||
continuing if the loop condition is true. When the loop condition evaluates to | ||
false, the loop completes. | ||
Similar to the | ||
[`if`/`else` proposal](https://github.com/carbon-language/carbon-lang/pull/285), | ||
the braces are optional and must be paired (`{ ... }`) if present. When there | ||
are no braces, only one statement is allowed. | ||
`continue` will continue with the next loop iteration directly, skipping any | ||
other statements in the loop body. The next loop iteration behaves as normal, | ||
starting with the condition being tested. | ||
`break` exits the loop immediately, without testing the condition. | ||
All of this is consistent with C/C++ behavior. | ||
### Executable semantics form | ||
``` | ||
%token WHILE | ||
%token CONTINUE | ||
%token BREAK | ||
statement: | ||
WHILE '(' expression ')' statement | ||
| CONTINUE ';' | ||
| BREAK ';' | ||
| /* pre-existing statements elided */ | ||
; | ||
``` | ||
Note that `continue` and `break` should only be valid in a loop context. | ||
## Caveats | ||
### C++ as baseline | ||
This baseline syntax is based on C++, following the migration sub-goal | ||
[Familiarity for experienced C++ developers with a gentle learning curve](/docs/project/goals.md#interoperability-with-and-migration-from-existing-c-code). | ||
To the extent that this proposal anchors on a particular approach, it aims to | ||
anchor on C++'s existing syntax, consistent with that sub-goal. | ||
Alternatives will generally reflect breaking consistency with C++ syntax. While | ||
most proposals may consider alternatives more, this proposal suggests a | ||
threshold of only accepting alternatives that skew from C++ syntax if they are | ||
clearly better; the priority in this proposal is to _avoid debate_ and produce a | ||
trivial proposal. Where an alternative would trigger debate, it should be | ||
examined by an advocate in a separate proposal. | ||
### `do`/`while` | ||
`do`/`while` is omitted from this proposal because of disagreement about whether | ||
it should be included in Carbon. It's better to have `do`/`while` considered | ||
separately as a result, in order to separate review of the non-contentious | ||
`while`. | ||
## Rationale based on Carbon's goals | ||
Relevant goals are: | ||
- [3. Code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write): | ||
- `while` loops are easy to read and very helpful. | ||
- [7. Interoperability with and migration from existing C++ code](/docs/project/goals.md#interoperability-with-and-migration-from-existing-c-code): | ||
- Keeping syntax close to C++ will make it easier for developers to | ||
transition. | ||
## Alternatives considered | ||
Both alternatives from the | ||
[`if`/`else` proposal](https://github.com/carbon-language/carbon-lang/pull/285) | ||
apply to `while` as well: we could remove parentheses, require braces, or both. | ||
The conclusions mirror here in order to avoid a divergence in syntax. | ||
Additional alternatives follow. | ||
### Non-C++ syntax | ||
Various non-C++ features that came up and are not suggested by this proposal | ||
because they aren't in C++ are: | ||
- `else` on `while`, as in Python. | ||
- A `loop` statement with `while(true)` behavior, as in Rust. | ||
- Labeled break and continue statements, as in Java or TypeScript. | ||
These may be added later, but they are not part of the | ||
[C++ baseline](#c-as-baseline), and have not received much consideration beyond | ||
that adopting the proposed syntax would not significantly impair adoption of | ||
such features. | ||
### Initializing variables in the `while` | ||
This proposal does not offer a way to initialize variables in the `while`. | ||
For comparison, C++ does allow declaring a variable in the condition, such as: | ||
```cc | ||
while (optional<T> next = get_next()) { ... } | ||
``` | ||
In addition, | ||
[Selections statements with initializer](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r1.html) | ||
could be inferred to suggest a corresponding `while (init; cond)` syntax. | ||
Neither of these is suggested in this proposal because we are likely to consider | ||
a _different_ route of allowing declaration of a variable in expressions. For | ||
example, the following would be legal not because `while` would use a | ||
`condition` semantic that allows variable declarations as a form, but because it | ||
uses `expression` semantics and `var` would be part of `expression` semantics: | ||
```carbon | ||
while (var optional<T> next = get_next()) { ... } | ||
``` | ||
In particular, this would also allow more flexible usage addressing more complex | ||
use-cases that C++ does not, such as: | ||
```carbon | ||
while ((var status_code c = bar()) != SUCCESS) { ... }` | ||
``` | ||
This breaks slightly from the [C++ baseline](#c-as-baseline) by offering a | ||
subset of C++ functionality. However, we can choose to add related functionality | ||
later if `expression` semantics end up not including `var`. Temporarily omitting | ||
`condition` functionality avoids having to reconcile it later if we pursue the | ||
`expression` route, and it is not crucial to `while` loop functionality. |