-
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.
- Loading branch information
Showing
2 changed files
with
242 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,241 @@ | ||
# if/else | ||
|
||
<!-- | ||
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/285) | ||
|
||
<!-- 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) | ||
- [if/else in expressions](#ifelse-in-expressions) | ||
- [Indentation](#indentation) | ||
- [Ambiguous else](#ambiguous-else) | ||
- [Alternatives considered](#alternatives-considered) | ||
- [No parentheses](#no-parentheses) | ||
- [Require braces](#require-braces) | ||
|
||
<!-- tocstop --> | ||
|
||
## Problem | ||
|
||
`if`/`else` is noted in the [language overview](/docs/design/README.md#ifelse), | ||
but is provisional. Control flow is important, and `if`/`else` is basic; the | ||
form is similar in many languages, even if details may change. | ||
|
||
## Background | ||
|
||
`if`/`else` is a common | ||
[conditional](<https://en.wikipedia.org/wiki/Conditional_(computer_programming)>), | ||
seen in | ||
[many languages](<https://en.wikipedia.org/wiki/Conditional_(computer_programming)#Choice_system_cross_reference>). | ||
A few syntaxes that are likely to influence `if`/`else` are: | ||
|
||
- C++ | ||
|
||
```cc | ||
if (x) { | ||
printf("x is true"); | ||
} else if (y) { | ||
printf("y is true"); | ||
} else { | ||
printf("Neither was true"); | ||
} | ||
``` | ||
|
||
- Python | ||
|
||
```python | ||
if x: | ||
print("x is true"); | ||
elif y: | ||
print("y is true"); | ||
else: | ||
print("Neither was true"); | ||
``` | ||
|
||
- Swift | ||
|
||
```swift | ||
if x { | ||
print("x is true") | ||
} else if y { | ||
print("y is true") | ||
} else { | ||
print("Neither was true") | ||
} | ||
``` | ||
|
||
- Rust -- versus other cases where `if` is a statement, Rust makes `if` an | ||
expression, allowing: | ||
|
||
```rust | ||
let x = if y { | ||
1 | ||
} else { | ||
0 | ||
}; | ||
``` | ||
|
||
## Proposal | ||
|
||
We should make `if`/`else` syntax consistent with C/C++, rather than adopting | ||
the syntax of another language. | ||
|
||
## Details | ||
|
||
`if`/`else` is a statement. The syntax looks like: | ||
|
||
`if` `(`_boolean expression_`)` `{` _statements evaluated when true_ `}` [ | ||
`else` `{` _statements evaluated when false_ `}` ] | ||
|
||
The braces are optional, but must be paired (`{ ... }`) if present. When there | ||
are no braces, only one statement is allowed. | ||
|
||
### Executable semantics form | ||
|
||
```bison | ||
statement: | ||
"if" '(' expression ')' statement optional_else | ||
| /* pre-existing statements elided */ | ||
; | ||
|
||
optional_else: | ||
/* empty */ | ||
| "else" statement | ||
; | ||
``` | ||
|
||
## 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. | ||
|
||
### if/else in expressions | ||
|
||
This proposal covers `if`/`else` as a statement. A Rust-like form of `if`/`else` | ||
as an expression could be supported, but is not part of this proposal because | ||
it's more complex. | ||
|
||
### Indentation | ||
|
||
It may be desirable to require meaningful indentation of the body of an | ||
`if`/`else`, in particular to help catch errors when there are no braces. | ||
|
||
For example, this could be a compiler error due to inconsistent indentation of | ||
the `do_parse` assignment: | ||
|
||
```carbon | ||
if (missing_data) | ||
Print("Missing data!"); | ||
do_parse = false; | ||
if (do_parse) | ||
ParseData(); | ||
``` | ||
|
||
This is _not_ part of this proposal. | ||
|
||
### Ambiguous else | ||
|
||
It may be desirable to reject cases where an `else` is ambiguous. For example, | ||
this could be a compiler error due to the ambiguous `else`: | ||
|
||
```carbon | ||
if (a) if (b) f(); else g(); | ||
``` | ||
|
||
This is _not_ part of this proposal. This proposal takes C++ syntax as a | ||
baseline, so an `else` binds to the innermost enclosing `if` that doesn't | ||
already have an `else`. | ||
|
||
This desire might also be addressed by choosing to require consistent | ||
indentation and disallowing multiple `if`s on the same line. | ||
|
||
## Alternatives considered | ||
|
||
See [C++ as baseline](#c-as-baseline) for an explanation of how alternatives are | ||
evaluated in this proposal. | ||
|
||
### No parentheses | ||
|
||
Parentheses could be optional (essentially not part of `if`/`else`, but addable | ||
as part of the expression), instead of required (as proposed). | ||
|
||
Advantages: | ||
|
||
- Removing parentheses gives developers less to type. | ||
- Consistent with several other languages, including Swift and Rust. | ||
|
||
Disadvantages: | ||
|
||
- Requiring parentheses is consistent with C++, and will be intuitive for C++ | ||
developers, from both a writability and readability perspective. | ||
- Parentheses help avoid ambiguities. | ||
- The Swift and Rust model is ambiguous if it's ever possible for an | ||
expression to optionally be followed by braces. That is possible in | ||
Rust, at least, where `Type{...}` is a valid expression. As a result, | ||
Rust rejects `if Type{.value = true}.value { thing1 } else { thing2 }` | ||
because it misinterprets the braces. | ||
- Parentheses allow making the braces optional without any risk of ambiguity. | ||
- Parentheses allow introducing syntactic variants in the future without | ||
ambiguity. | ||
- For example, C++'s `if constexpr (...)` wouldn't have been possible if | ||
the parentheses were optional. | ||
|
||
The benefits of this are debatable, and it should be examined by an advocate in | ||
a focused proposal. For now, we should match C++'s decision. | ||
|
||
### Require braces | ||
|
||
Braces could be required, instead of optional (as proposed). | ||
|
||
Advantages: | ||
|
||
- Braces avoid syntax ambiguities. | ||
- For example, `if (x) if (y) { ... } else { ... }` has | ||
difficult-to-understand binding of `else`. | ||
- Braces avoid errors when adding statements. | ||
|
||
- For example, if: | ||
|
||
```carbon | ||
if (x) | ||
do_parse = false; | ||
``` | ||
|
||
has a statement added: | ||
|
||
```carbon | ||
if (missing_data) | ||
Print("Missing data!"); | ||
do_parse = false; | ||
``` | ||
|
||
Disadvantages: | ||
|
||
- Inconsistent with C++. | ||
|
||
The benefits of this are debatable, and it should be examined by an advocate in | ||
a focused proposal. For now, we should match C++'s decision. |