Przeglądaj źródła

Require braces (#623)

Require braces, never optional, particularly in control flow like `if`/`else`.

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
Jon Meow 4 lat temu
rodzic
commit
cc56afb79e
2 zmienionych plików z 210 dodań i 0 usunięć
  1. 1 0
      proposals/README.md
  2. 209 0
      proposals/p0623.md

+ 1 - 0
proposals/README.md

@@ -61,5 +61,6 @@ request:
 -   [0555 - Operator precedence](p0555.md)
 -   [0601 - Operator tokens](p0601.md)
 -   [0618 - var ordering](p0618.md)
+-   [0623 - Require braces](p0623.md)
 
 <!-- endproposals -->

+ 209 - 0
proposals/p0623.md

@@ -0,0 +1,209 @@
+# 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)
+    -   [Consistency](#consistency)
+    -   [C++ style rules](#c-style-rules)
+    -   [`goto fail`](#goto-fail)
+-   [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)
+    -   [`elif`](#elif)
+
+<!-- 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
+
+### Consistency
+
+We were adopting the C++ syntax primarily for easy consistency with C++. For
+other languages:
+
+-   Some modern languages require braces, including Go, Rust, and Swift. Note
+    some which require braces make parentheses optional.
+-   Kotlin is an example modern language which does not require braces.
+-   Older languages tend to make braces optional, including Java, JavaScript,
+    and C#.
+
+### C++ style rules
+
+There is a
+[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)
+for when to use braces.
+
+### `goto fail`
+
+Apple had an infamous `goto fail` bug:
+
+-   https://www.imperialviolet.org/2014/02/22/applebug.html
+-   https://dwheeler.com/essays/apple-goto-fail.html
+
+## 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`.
+
+We will allow `else if` as a special structure for repeated `if` statements due
+to their frequency. For example, `if (...) { ... } else if (...) { ... }`
+behaves identically to `if (...) { ... } else { if (...) { ... } }`.
+
+## Rationale based on Carbon's goals
+
+-   **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`-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:
+
+-   Gives two ways of doing the same thing.
+    -   Style guides will make choices, creating more contextual coding style.
+    -   Some community members opined that requiring braces was the only
+        solution which is both appealing and easy to automate formatting for.
+        -   A contrary opinion is that single-line if statements without braces
+            are more appealing, and not significantly more difficult to
+            automate.
+-   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;
+    ```
+
+    -   Developers commonly want to add debugging statements to conditionals,
+        and missing braces can lead to these kinds of errors.
+    -   It's possible that, over time, adding braces to add debug statements
+        then removing the debug statements without removing statements will lead
+        to braces remaining when braces are optional.
+        -   This can be addressed by style guides and automated formatting that
+            inserts or removes braces as appropriate, cleaning up after
+            temporary edits.
+        -   Some people feel the churn of adding braces and later removing them
+            is a significant toil that can be avoided by always adding them,
+            such as [here](https://wiki.c2.com/?AlwaysUseBracesOnIfThen).
+    -   It can more easily lead to bugs like `goto fail;`.
+        -   However, as the blog post points out, one can have incorrect
+            indentation with braces too.
+
+### Optional parentheses
+
+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.
+
+### `elif`
+
+We could make `else if` a single token, such as `elseif` or `elif`.
+
+Advantages:
+
+-   Can parse as a single token.
+
+Disadvantages:
+
+-   Visual inconsistency with C++.
+    -   `else if` also appears in some languages that require braces, such as
+        Go, Rust, and Swift.