mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 17:31:07 +01:00
One way principle (#829)
Add a principle that Carbon should only provide one way of doing things Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
This commit is contained in:
committed by
GitHub
co-authored by
Chandler Carruth
parent
6d33a80988
commit
c3f4f28ec5
@@ -0,0 +1,155 @@
|
||||
# Principle: Prefer providing only one way to do a given thing
|
||||
|
||||
<!--
|
||||
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
|
||||
-->
|
||||
|
||||
<!-- toc -->
|
||||
|
||||
## 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)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
## 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)
|
||||
@@ -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)
|
||||
|
||||
<!-- endproposals -->
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
# One way principle
|
||||
|
||||
<!--
|
||||
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/829)
|
||||
|
||||
<!-- toc -->
|
||||
|
||||
## 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)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
## 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.
|
||||
Reference in New Issue
Block a user