|
|
@@ -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.
|