mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 19:41:05 +01:00
As requested at https://github.com/carbon-language/carbon-lang/pull/2332#discussion_r1002257672, "Very minor, but "C/C++" irritates some people in the C++ community so we may as well avoid it here."
254 lines
7.2 KiB
Markdown
254 lines
7.2 KiB
Markdown
# 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)
|
|
- [Rationale](#rationale)
|
|
|
|
<!-- tocstop -->
|
|
|
|
## Problem
|
|
|
|
`if`/`else` is noted in the [language overview](/docs/design/README.md), 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 and 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
|
|
| /* preexisting 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.
|
|
|
|
## Rationale
|
|
|
|
This proposal focuses on an uncontroversial piece that we are going to carry
|
|
from C++, as a baseline for future Carbon evolution. It serves our migration
|
|
goals (especially "Familiarity for experienced C++ developers with a gentle
|
|
learning curve") by avoiding unnecessary deviation from C++, and instead
|
|
focusing on subsetting the C++ feature. While we expect this feature to evolve
|
|
somewhat, the changes we're likely to want can easily be applied incrementally,
|
|
and this is a fine starting point that anchors us on favoring syntax familiar to
|
|
C++ developers.
|