diff --git a/docs/project/principles/one_way.md b/docs/project/principles/one_way.md new file mode 100644 index 000000000000..36e7399b4491 --- /dev/null +++ b/docs/project/principles/one_way.md @@ -0,0 +1,155 @@ +# Principle: Prefer providing only one way to do a given thing + + + + + +## Table of contents + +- [Background](#background) +- [Principle](#principle) +- [Applications of this principle](#applications-of-this-principle) +- [Caveats](#caveats) + - [Specialized syntax](#specialized-syntax) + - [Non-obvious alternatives](#non-obvious-alternatives) + - [In evolution](#in-evolution) +- [Alternatives considered](#alternatives-considered) + + + +## Background + +It's common in programming languages to provide multiple, similar ways of doing +the same thing. Sometimes this reflects the legacy of a language, and +difficulties in evolving in ways that would require changes to +developer-authored code, thereby retaining backwards compatibility. Other times +it reflects a desire to provide both verbose and concise versions of the same +syntax. We are concerned with both forms. + +We also are cautious about creating alternatives that may give rise to a +[paradox of choice](https://en.wikipedia.org/wiki/The_Paradox_of_Choice), +wherein options are similar enough that developers actively spend time analyzing +tarde-offs, and the time spent that way outweighs the potential benefits of a +correct choice. + +Where multiple, similar implementation options exist, it can sometimes give rise +to style guidelines to indicate a preferential choice; sometimes because one +option is objectively better, but sometimes because making a choice is better +than not making one. Even with a style guide, developers may diverge in style by +accident or intent, choosing different coding patterns simply because either +option works. It can also become an issue as developers move between an +organization that they need to learn a new style guide, and relearn habits. + +A couple examples of this in other languages are: + +- In Perl, + ["There is more than one way to do it."](https://en.wikipedia.org/wiki/There%27s_more_than_one_way_to_do_it) +- In Python, + ["There should be one -- and preferably only one -- obvious way to do it."](https://www.python.org/dev/peps/pep-0020/) + +## Principle + +In Carbon, we will prefer providing only one way to do a given thing. That is, +given a syntax scenario where multiple design options are available, we will +tend to provide _one_ option rather than than providing several and letting +users choose. This echoes Python's principle. + +Minimizing choices serves several goals: + +- [Language tools](/docs/project/goals.md#language-tools-and-ecosystem) should + be easier to write and maintain with the lower language complexity implied + by less duplication of functionality. +- [Software and language evolution](/docs/project/goals.md#software-and-language-evolution) + processes should find it easier to both consider existing syntax and avoid + creation of new syntax conflicts. +- [Understandability of code](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write) + should be promoted if developers have less syntax they need to understand. + This can be expected to improve code quality and productivity so long as the + resulting code structures aren't overly complicated. + +By minimizing the overlap of language features, we hope to make work easier for +both Carbon's maintainers and developers. + +## Applications of this principle + +We can observe the application of this principle by comparing several language +features to C++. There, improving understandability is frequently the primary +motivation: + +- Where C++ allows logical operators to be written with either symbols (for + example, `&&`) or text (for example, `and`), Carbon will only support one + form (in this case, [text](/proposals/p0680.md)). +- Where C++ allows hexadecimal numeric literals to be either lowercase + (`0xaa`) or uppercase (`0xAA`), and with `x` optionally uppercase as well, + Carbon will only allow the [`0xAA` casing](/proposals/p0143.md). +- Where C++ provides both `struct` and `class` with the only difference is + access control defaults, Carbon will only provide one (`class`, albeit with + default public visibility diverging from C++). + +However, sometimes language tools are the primary motivation. For example, where +C++ allows braces to be omitted for single-statement control flow blocks, Carbon +will [require braces](/proposals/p0623.md). This offers a syntax simplification +that should allow for better error detection. + +## Caveats + +### Specialized syntax + +Sometimes overlap will occur because a specialized syntax offers particular +benefits, typically as a matter of convenience for either a common use-case or a +particularly complex and important use-case. Some examples of why and where this +occurs are: + +- For [performance](/docs/projects/goals.md#performance-critical-software), it + may at times be necessary to provide a specialized syntax that better + supports optimization than a generic syntax. +- For + [understandability of code](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write), + there may be times that a particular use-case is common enough that + simplifying its syntax provides substantial benefit. + - For example, `for (var x: auto in list)` could typically be written with + as a `while` loop, but range-based for loops are considered to improve + understandability. However, C++'s `for (;;)` syntax is sufficiently + close to `while` that we expect to use `while` to address the + corresponding use-cases. +- For + [migration and interoperability](/docs/project/goals.md#interoperability-with-and-migration-from-existing-c-code), + it may be pragmatic to provide both an ideal way of doing things for new + Carbon code, and a separate approach that is more C++-compatible for + migration. + - For example, consider generics and templates: generics are considered to + be the preferred form for new code, but templates are considered a + necessity for migration of C++ code. This is not an evolution situation + because we do not anticipate ever removing templates. + +### Non-obvious alternatives + +Echoing Python, there may be non-obvious alternative ways of doing a given +thing, such as using `while (condition) { DoSomething(); break; }` in place of +`if (condition) { DoSomething(); }`. As a more complex example, lambdas could be +implemented using other code constructs; this would require significantly more +code and hinder understandability. + +This kind of overlap may exist, but will hopefully be considered sufficiently +non-idiomatic that examples won't be common in code. If a choice would not +likely be based mainly on coding styles, it's likely sufficiently distinct that +this principle won't apply. + +### In evolution + +For [evolution](/docs/project/goals.md#software-and-language-evolution), it will +often be necessary to temporarily provide an "old" and "new" way of doing things +simultaneously. + +For example, if renaming a language feature, it may be appropriate to provide +the same functionality under two identifiers. However, one should be marked as +deprecated and eventually removed. We should be cautious of adding new, +overlapping features without a plan to remove the corresponding legacy version. + +## Alternatives considered + +- [Provide multiple ways of doing a given thing](/proposals/p0829.md#provide-multiple-ways-of-doing-a-given-thing) diff --git a/proposals/README.md b/proposals/README.md index 5a02b6c54fe3..1fc79ab70426 100644 --- a/proposals/README.md +++ b/proposals/README.md @@ -71,5 +71,6 @@ request: - [0731 - Generics details 2: adapters, associated types, parameterized interfaces](p0731.md) - [0752 - `api` file default-`public`](p0752.md) - [0777 - Inheritance](p0777.md) +- [0829 - One way principle](p0829.md) diff --git a/proposals/p0829.md b/proposals/p0829.md new file mode 100644 index 000000000000..fd17a5839df1 --- /dev/null +++ b/proposals/p0829.md @@ -0,0 +1,79 @@ +# One way principle + + + +[Pull request](https://github.com/carbon-language/carbon-lang/pull/829) + + + +## Table of contents + +- [Problem](#problem) +- [Proposal](#proposal) +- [Alternatives considered](#alternatives-considered) + - [Provide multiple ways of doing a given thing](#provide-multiple-ways-of-doing-a-given-thing) + + + +## Problem + +We have repeatedly run into cases where we could offer equivalent functionality +multiple ways. + +## Proposal + +Add a principle noting the preference is to only provide one way of doing +things. + +## Alternatives considered + +### Provide multiple ways of doing a given thing + +Carbon could focus on providing a lower bar for overlapping functionality, +encouraging overlapping syntax. This could be considered as similar to Perl's +["There is more than one way to do it."](https://en.wikipedia.org/wiki/There%27s_more_than_one_way_to_do_it). +Overlapping syntax should still receive some scrutiny, but use-cases with small +marginal benefits might be considered sufficient to create divergent syntax. + +For example: + +- For matching C++ legacy: + - We might include `for (;;)`. + - We might re-add support for optional braces on `if` and similar. + - We might support `class` and `struct` with their C++-equivalent default + visibility rules. + - We might support both `and` and `&&`, `0xa` and `0XA`, etc. +- We might make `;` optional, as there's precedent in modern languages to do + so. +- Both templates and generics might be embraced with feature parity such that + both should be good solutions for generic programming problems, as much as + possible. + +It's worth noting Perl also has a related motto of "There is more than one way +to do it, but sometimes consistency is not a bad thing either." It's best to +avoid interpreting this alternative to the extreme: for example, this is not +encouraging providing all of `extensible`, `extendable`, and `extendible` as +equivalent keywords, as that is divergence with very minimal benefit +(particularly `extendable` versus `extendible`). + +Advantages: + +- More likely that developers will find syntax that they like. +- Can make it easier to migrate code because we can actively support a + C++-like dialect in addition to a more Carbon-centric dialect. + +Disadvantages: + +- Developers would either accept personal styles, or create more style guides. + - Either can be considered a language dialect, whether at the personal or + organizational level. +- Increases the difficulty of building syntax parsing and typo correction in + the language, as there are more options that need to be corrected between, + multiple of which may be valid in a given context. + +We are declining this alternative because we value the language simplicity +provided by minimizing overlap of features.