Skip to content

Commit

Permalink
Move the forward from file scope to future work
Browse files Browse the repository at this point in the history
  • Loading branch information
danakj committed Jan 20, 2025
1 parent e3b5d48 commit 7d390dd
Showing 1 changed file with 118 additions and 40 deletions.
158 changes: 118 additions & 40 deletions proposals/p4682.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- [Avoiding confusion with other domains](#avoiding-confusion-with-other-domains)
- [Proposal](#proposal)
- [Rationale](#rationale)
- [Future work](#future-work)
- [Automatically importing names from the `prelude` into file scope](#automatically-importing-names-from-the-prelude-into-file-scope)
- [Namespacing the `Core` package.](#namespacing-the-core-package)
- [Alternatives considered](#alternatives-considered)
- [`[T; N]`](#t-n)
- [`array [T; N]`](#array-t-n)
Expand Down Expand Up @@ -279,29 +282,18 @@ array, and then a shorthand for referring to that library type.
In line with other languages surveyed above, given the presence of a
direct-storage immutably-sized array in Carbon, we will reserve the unqualified
name "array" for this type. In full, its name is `Core.Array(T, N)`, where `T`
is the type of elements in the array, and `N` is the number of elements.

Because arrays will be very common in Carbon code, we want to privilege their
usage. We stated above that we want "arrays to have a concise name, but they do
not need to be comparably concise to primitives and tuples". As such, we will
allow the use of `Array` without naming `Core` through the use of a builtin
shortcut that simply forwards `Array(T, N)` to `Core.Array(T, N)`. Notably this
leaves room for supporting multi-dimensional arrays by adding further optional
size parameters, either in the `Array` type or in a similar sibling type.

Since the `Core.Array` type has a builtin shorthand, and the type it resolves to
should always be available, `Core.Array` will be placed in the `prelude` library
of `Core`. The `Core.Array` library type will need to interact with the compiler
through builtins in order to define its direct storage, but its methods can
largely be written directly in the `Core` package.
is the type of elements in the array, and `N` is the number of elements. Notably
this leaves room for supporting multi-dimensional arrays by adding further
optional size parameters, either in the `Array` type or in a similar sibling
type.

Here is a provisional vocabulary table to compare with other languages:

| Owning type | Runtime Sized | Compile-time Sized |
| ------------------------ | ------------- | ------------------ |
| Direct, Immutable Size | - | `Array(T, N)` |
| Indirect, Immutable Size | ? | `Box(Array(T, N))` |
| Indirect, Mutable Size | `Buf(T)` | - |
| Owning type | Runtime Sized | Compile-time Sized |
| ------------------------ | ------------- | ----------------------- |
| Direct, Immutable Size | - | `Core.Array(T, N)` |
| Indirect, Immutable Size | ? | `Core.Box(Array(T, N))` |
| Indirect, Mutable Size | `Core.Buf(T)` | - |

Carbon does not have proposed names for heap allocated storage, so we use some
placeholders here, in order to show where `Array` fits into the picture:
Expand All @@ -317,35 +309,42 @@ This is in contrast with Rust where `&[T]` is a slice, and thus `[T]` is a
fixed-size buffer, so it then follows that `Box<[T]>` is a heap-allocated
fixed-size buffer.

Because arrays will be very common in Carbon code, we want to privilege their
usage. There are at least two ways in which we can do so. The first is to
include them in the `prelude` library of the `Core` package. This ensures they
are available in every Carbon file as `Core.Array`. The second is by making the
type available through a shorthand without going through the `Core` package
name. Here we propose to do the former, and leave the latter to future work.

## Rationale

As this proposal is addressing the question of introducing a new builtin and
library type, it is mostly focused on the goal
As this proposal is addressing the question of introducing a new `prelude`
library type in `Core`, it is mostly focused on the goal
[Code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write)

This proposal aims to make code easy to understand by having the builtin
forwarding name match exactly with the type in the `Core` library. This choice
makes the builtin conceptually equivalent to an implicit `import` of the type
into the file scope, much like the implicit `import` of the `prelude` library of
the `Core` package, something developers will already need to model in their
minds when reading Carbon code. That `Array` will be provided as a compiler
builtin is an implementation detail that the Carbon developer need not worry
about. It could as easily be implemented as an implicit `import`.

By having the builtin shorthand use the same name as the library type, we make
the builtin the least magical it could possibly be, while still maintaining its
primary benefit of conciseness.
This proposal aims to make code easy to understand by using a name that is
consistent across systems programming languages, and avoiding names that have
conflicting meaning. It also uses a standard type syntax, with a type in the
`Core` package, making the type and its documentation maximally discoverable
without requiring special-casing.

We introduced some more specific sub-goals above:

1. Privileging the most common type names

This proposal privileges `Array` in line with the frequency it will appear in
code: The written name of arrays are shortened to avoid writing `Core.`, because
of the expected high frequency of arrays in Carbon code. But it avoids
introducing additional syntax (such as with `[T; N]` or `(1, 2)`) or breaking
naming rules (such as with a lowercase type name) because the frequency of use
of arrays will be much lower than that of primitives and tuples.
This proposal privileges `Core.Array` as it will appear frequently in code, by
placing it in the `prelude` library. This avoids the need for developers to
`import` another `Core` library in order to access the type.

While we might argue that `Core.Array` should be further privileged with a
shorthand that avoids any scope prefixes, due to the expected high frequency of
arrays in Carbon code, we leave that to [future work](#future-work) for a more
general feature.

In this proposal, we avoid introducing additional syntax (such as with `[T; N]`
or `(1, 2)`) or breaking naming rules (such as with a lowercase type name)
because the frequency of use of arrays will be much lower than that of
primitives and tuples.

2. Absence of syntax should make clear defaults

Expand Down Expand Up @@ -373,6 +372,85 @@ core systems programming language construct is fraught. Either the name is to be
incorrectly confused with a mathematical vector or with a C++ `std::vector`. We
avoid the confusion by avoiding this name.

## Future work

### Automatically importing names from the `prelude` into file scope

We stated above that we want "arrays to have a concise name, but they do not
need to be comparably concise to primitives and tuples". As such, accessing the
`Array` type without naming `Core` may be a productive option for Carbon
developers, both for writing and reading Carbon code.

The act of importing the `Array` type from `Core` into every Carbon file scope
has some challenges as a one-off exception, and thus could use a more general
and robust follow-on proposal. The challenges identified here are:

- `Array` is only one name from the `prelude` that may be productive to
automatically import into the file scope. There are also traits in the
`prelude` that are commonly used, such as `Core.As`. We would like to see a
design that allows a clear way to specify what names are imported into the
file scope and allows future names to be added to that set in a
clearly-specified way.

For comparison, this is done in Rust by importing all names in the
[`std::prelude` module](https://doc.rust-lang.org/stable/std/prelude/index.html)
into the file scope. The names in the `prelude` are
[aliases to](https://doc.rust-lang.org/stable/std/prelude/v1/index.html)
other parts of the standard library. Each edition of Rust has its
[own `prelude` sub-module](https://doc.rust-lang.org/stable/core/prelude/rust_2021/index.html)
that re-exports the previous prelude and adds any new symbols. In a similar
way, a namespace in Carbon's `prelude` library, or a separate library, could
be used to specify aliases that are imported into the file scope.

- Developers may want to opt out of importing names from the `prelude` into
the file scope if they'd like to use those names for themselves. We should
consider if and how to provide a mechanism to opt out of the import of any
`prelude` names (including `Core`) into the file scope.

- We should specify a more general criteria for considering what names to
import from the `prelude` into the file scope automatically. This proposal
states that the frequency-of-use of a name make a good metric, but doesn't
give a clearer rule that would we could measure names against. Rust uses a
metric that is also based on frequency-of-use for its automatically-imported
`prelude`:

> The prelude is the list of things that Rust automatically imports into
> every Rust program. It’s kept as small as possible, and is focused on
> things, particularly traits, which are used in almost every single Rust
> program.
>
> _-- From
> [std::prelude](https://doc.rust-lang.org/stable/std/prelude/index.html)_
- Given such a feature, we could consider moving `i8`, `bool`, etc to be
aliases in the `prelude` that are in the set of names automatically imported
into the file scope.

This feature would aim to make code easy to understand by having the names in
the file scopematch exactly with the names in the `Core` library, minus the
scope prefixes. This choice to make the shorthands be an implicit `import` of
the type into the file scope matches the existing implicit `import` of the
`prelude` library of the `Core` package, something developers will already need
to model in their minds when reading Carbon code.

Ultimately, it would be an implementation detail if this is done through an
import of a part of `Core`, or through the compiler's builtin mechanisms. The
mechanism for opting-out of the import could be expected to influence the way
this feature would be implemented.

By having such shorthands use the same names as the library, we make the
shorthands the least magical they could possibly be, while still maintaining
their primary benefit of conciseness.

### Namespacing the `Core` package.

At this time, the `Core` package remains small, but there will come a time where
the names within need to be split into smaller namespaces. Then the name
`Core.Array`, among others, will become longer and the act of previleging the
name through importing it into the file scope will become more pronounced. At
this time, we don't propose to put `Array` into a namespace in `Core` as there's
no such existing structure to point to yet.

## Alternatives considered

### `[T; N]`
Expand Down

0 comments on commit 7d390dd

Please sign in to comment.