Skip to content

Commit

Permalink
if/else (#285)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonmeow authored Mar 24, 2021
1 parent cba22f7 commit a20ae0f
Show file tree
Hide file tree
Showing 2 changed files with 242 additions and 0 deletions.
1 change: 1 addition & 0 deletions proposals/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,6 @@ request:
- [0199 - Decision](p0199_decision.md)
- [0253 - 2021 Roadmap](p0253.md)
- [0253 - Decision](p0253_decision.md)
- [0285 - if/else](p0285.md)

<!-- endproposals -->
241 changes: 241 additions & 0 deletions proposals/p0285.md
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.

0 comments on commit a20ae0f

Please sign in to comment.