Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Require braces #623

Merged
merged 19 commits into from
Jul 22, 2021
1 change: 1 addition & 0 deletions proposals/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,6 @@ request:
- [0540 - Remove `Void`](p0540.md)
- [0555 - Operator precedence](p0555.md)
- [0601 - Operator tokens](p0601.md)
- [0623 - Require braces](p0623.md)

<!-- endproposals -->
150 changes: 150 additions & 0 deletions proposals/p0623.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Require braces

<!--
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/623)

<!-- toc -->

## Table of contents

- [Problem](#problem)
- [Background](#background)
- [Proposal](#proposal)
- [Rationale based on Carbon's goals](#rationale-based-on-carbons-goals)
- [Alternatives considered](#alternatives-considered)
- [Optional braces](#optional-braces)
- [Optional parentheses](#optional-parentheses)

<!-- tocstop -->

## Problem

In C++, braces are often optional, such as in:

```
for (Shape x : shapes)
Draw(x);
```

Carbon adopted this design choice by default in proposals
[#285](https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p0285.md),
[#340](https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p0340.md),
and
[#353](https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p0353.md).
But should we keep it?

## Background

We were adopting the C++ syntax primarily for easy consistency with C++.

Some modern languages require braces, including Go, Rust, and Swift. Kotlin is
an example which does not. Note some which require braces make parentheses
chandlerc marked this conversation as resolved.
Show resolved Hide resolved
optional.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems worth including as background the CERT rule:
https://wiki.sei.cmu.edu/confluence/display/c/EXP19-C.+Use+braces+for+the+body+of+an+if%2C+for%2C+or+while+statement

And the blog post about goto fail;: https://www.imperialviolet.org/2014/02/22/applebug.html

FWIW, I'm not suggesting that goto fail; should be a strong rationale for this pattern, but I do think it should be addressed explicitly as it is often cited as a reason for this change. FWIW, I agree with @zygoloid below that simplifying the language grammar seems like a strong motivation. I actually like the summary of the importance of braces here in the blog post:

Maybe the coding style contributed to this by allowing ifs without braces, but one can have incorrect indentation with braces too, so that doesn't seem terribly convincing to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems worth including as background the CERT rule:
https://wiki.sei.cmu.edu/confluence/display/c/EXP19-C.+Use+braces+for+the+body+of+an+if%2C+for%2C+or+while+statement

Linked.

And the blog post about goto fail;: https://www.imperialviolet.org/2014/02/22/applebug.html

Added, moved up the link that was in rationale.

FWIW, I'm not suggesting that goto fail; should be a strong rationale for this pattern, but I do think it should be addressed explicitly as it is often cited as a reason for this change. FWIW, I agree with @zygoloid below that simplifying the language grammar seems like a strong motivation. I actually like the summary of the importance of braces here in the blog post:

Maybe the coding style contributed to this by allowing ifs without braces, but one can have incorrect indentation with braces too, so that doesn't seem terribly convincing to me.

Are you saying to remove the mention of goto fail from the rationale? Do you want this sentence somewhere in particular?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, I'm happy mentioning it, I just didn't want to overstate its importance. I've suggested a place where it could even be included in the disadvantages section, but that's optional given the comment in the rationale. Up to you.


## Proposal

Carbon should require braces when they might otherwise be optional. We should
continue to require parentheses. This currently comes up in `if`/`else`,
`while`, and `for`.

## Rationale based on Carbon's goals
josh11b marked this conversation as resolved.
Show resolved Hide resolved

- **Software and language evolution**: Reducing parsing ambiguity of curly
braces is important for expanding the syntactic options for Carbon.

- **Code that is easy to read, understand, and write**: We have a preference
to give only one way to do things, and optional braces are inconsistent with
that. It's also easier to understand and parse code that uses braces, and
defends against the possibility of
[`goto fail`](https://dwheeler.com/essays/apple-goto-fail.html)-style bugs,
whether accidental or malicious.

- **Interoperability with and migration from existing C++ code**: While C++
does make braces optional in related situations, we believe this isn't
fundamental to migration or familiarity for C++ developers, so this goal is
not meaningfully impacted by this change.

## Alternatives considered

### Optional braces

We could instead keep braces optional, such as:

```carbon
if (x)
return y;
```

Advantages:

- Consistent with C++.
- Allows for greater brevity in code, such as `if (!success) return error;`.

Disadvantages:
chandlerc marked this conversation as resolved.
Show resolved Hide resolved

- Gives two ways of doing the same thing.
- Style guides will make choices, creating more contextual coding style.
chandlerc marked this conversation as resolved.
Show resolved Hide resolved
- More complex and harder to parse.

- Nested `if` statements can have unclear `else` bindings. For example:

```carbon
if (x)
if (y)
DoIfY();
else
DoIfNotY();
else
DoIfNotX();
```

- If Carbon were to reuse `if` and `else` keywords for a ternary operator,
that could omit braces in order to avoid ambiguity. For example,
`int x = if y then 3 else 7;`.

- Developers are known to make mistakes adding statements to conditionals
missing braces, keeping consistent indentation, and missing the incorrect
behavior due to cognitive load. For example:

```carbon
if (x)
return y;
```

->

```carbon
if (x)
print("Returning y");
return y;
```

### Optional parentheses
zygoloid marked this conversation as resolved.
Show resolved Hide resolved

Languages which make braces required can make parentheses optional, or even
disallow them, such as:

```carbon
if x {
return y;
}
```

Advantages:

- Exchanges verbosity in syntax, requiring `{}` but removing `()`.
- Particularly useful in that many conditionals have `{}` regardless of
optionality, but all conditionals could in theory remove `()`.
- Cross-language consistency with languages that require `{}`.

Disadvantages:

- Visual inconsistency with C++.
- Parentheses make parsing less likely to encounter ambiguity.
- Optional parentheses lead to two ways of doing the same thing, although
disallowing them entirely could address this.