Skip to content

Commit d3d8d44

Browse files
committed
Add two draft project goals: seamless C support, and relaxing the orphan rule
Both WIP, both without owners yet. These are meant as samples of goals, and as samples of goals without owners specifically. However, they're also goals that people have expressed support for solving.
1 parent 761a32b commit d3d8d44

File tree

3 files changed

+274
-1
lines changed

3 files changed

+274
-1
lines changed
+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# Relaxing the Orphan Rule
2+
3+
| Metadata | |
4+
| --- | --- |
5+
| Owner(s) | |
6+
| Teams | *lang* |
7+
| Status | WIP |
8+
9+
## Motivation
10+
11+
Relax the orphan rule, in limited circumstances, to allow crates to provide
12+
implementations of third-party traits for third-party types. The orphan rule
13+
averts one potential source of conflicts between Rust crates, but its presence
14+
also creates scaling issues in the Rust community: it prevents providing a
15+
third-party library that integrates two other libraries with each other, and
16+
instead requires convincing the author of one of the two libraries to add
17+
(optional) support for the other, or requires using a newtype wrapper. Relaxing
18+
the orphan rule, carefully, would make it easier to integrate libraries with
19+
each other, share those integrations, and make it easier for new libraries to
20+
garner support from the ecosystem.
21+
22+
### The status quo
23+
24+
Suppose a Rust developer wants to work with two libraries: `lib_a` providing
25+
trait `TraitA`, and `lib_b` providing type `TypeB`. Due to the orphan rule, if
26+
they want to use the two together, they have the following options:
27+
28+
- Convince the maintainer of `lib_a` to provide `impl TraitA for TypeB`. This
29+
typically involves an optional dependency on `lib_b`. This usually only
30+
occurs if `lib_a` is substantially less popular than `lib_b`, or the
31+
maintainer of `lib_a` is convinced that others are likely to want to use the
32+
two together. This tends to feel "reversed" from the norm.
33+
34+
- Convince the maintainer of `lib_b` to provide `impl TraitA for TypeB`. This
35+
typically involves an optional dependency on `lib_a`. This is only likely to
36+
occur if `lib_a` is popular, and the maintainer of `lib_b` is convinced that
37+
others may want to use the two together. The difficulty in advocating this,
38+
scaled across the community, is one big reason why it's difficult to build
39+
new popular crates built around traits (e.g. competing
40+
serialization/deserialization libraries, or competing async I/O traits).
41+
42+
- Vendor either `lib_a` or `lib_b` into their own project. This is
43+
inconvenient, adds maintenance costs, and isn't typically an option for
44+
public projects intended for others to use.
45+
46+
- Create a newtype wrapper around `TypeB`, and implement `TraitA` for the
47+
wrapper type. This is less convenient, propagates throughout the crate (and
48+
through other crates if doing this in a library), and may require additional
49+
trait implementations for the wrapper that `TypeB` already implemented.
50+
51+
All of these solutions are suboptimal in some way, and inconvenient. In
52+
particular, all of them are much more difficult than actually writing the trait
53+
impl. All of them tend to take longer, as well, slowing down whatever goal
54+
depended on having the trait impl.
55+
56+
### The next few steps
57+
58+
As an initial experiment, try relaxing the orphan rule for binary crates, since
59+
this cannot create library incompatibilities in the ecosystem. Allow binary
60+
crates to implement third-party traits for third-party types, possibly
61+
requiring a marker on either the trait or type or both. See how well this works
62+
for users.
63+
64+
As a second experiment, try allowing library crates to provide third-party
65+
impls as long as no implementations actually conflict. Perhaps require marking
66+
traits and/or types that permit third-party impls, to ensure that crates can
67+
always implement traits for their own types.
68+
69+
### The "shiny future" we are working towards
70+
71+
Long-term, we'll want a way to resolve conflicts between third-party trait
72+
impls.
73+
74+
We should support a "standalone derive" mechanism, to derive a trait for a type
75+
without attaching the derive to the type definition. We could save a simple
76+
form of type information about a type, and define a standalone deriving
77+
mechanism that consumes exclusively that information.
78+
79+
Given such a mechanism, we could then permit any crate to invoke the standalone
80+
derive mechanism for a trait and type, and allow identical derivations no
81+
matter where they appear in the dependency tree.
82+
83+
## Design axioms
84+
85+
- **Rustaceans should be able to easily integrate a third-party trait with a
86+
third-party type without requiring the cooperation of third-party crate
87+
maintainers.**
88+
89+
- **It should be possible to *publish* such integration as a new crate.** For
90+
instance, it should be possible to publish an `a_b` crate integrating `a`
91+
with `b`. This makes it easier to scale the ecosystem and get adoption for
92+
new libraries.
93+
94+
- **Crate authors should have some control over whether their types have
95+
third-party traits implemented.** This ensures that it isn't a breaking
96+
change to introdice first-party trait implementations.
97+
98+
[da]: ../about/design_axioms.md
99+
100+
## Ownership and other resources
101+
102+
**Owner:** TODO
103+
104+
### Support needed from the project
105+
106+
* Lang team:
107+
* Design meetings to discuss design changes
108+
* RFC reviews
109+
* Blog post inviting testing, evaluation, and feedback
110+
111+
## Outputs and milestones
112+
113+
### Outputs
114+
115+
The output will be a pair of RFCs:
116+
- A lang RFC proposing a very simple system for binaries to ignore the orphan rule.
117+
- A lang RFC proposing a system with more careful safeguards, to relax the orphan rule for publishable library crates.
118+
119+
### Milestones
120+
121+
- Accepted RFCs.
122+
123+
## Frequently asked questions
124+
125+
### Won't this create incompatibilities between libraries that implement the same trait for the same type?
126+
127+
Yes! The orphan rule is a tradeoff. It was established to avert one source of
128+
potential incompatibility between library crates, in order to help the
129+
ecosystem grow, scale, and avoid conflicts. However, the presence of the orphan
130+
rule creates a different set of scaling issues and conflicts. This project goal
131+
proposes to adjust the balance, attempting to achieve some of the benefits of
132+
both.

src/2024h2/Seamless-C-Support.md

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# Seamless C support
2+
3+
| Metadata | |
4+
| --- | --- |
5+
| Owner(s) | *Github usernames or other identifying info for goal owners* |
6+
| Teams | *Names of teams being asked to commit to the goal* |
7+
| Status | WIP |
8+
9+
## Motivation
10+
11+
Using C from Rust should be as easy as using C from C++: completely seamless,
12+
as though it's just another module of code. You should be able to drop Rust
13+
code into a C project and start compiling and using it in minutes.
14+
15+
### The status quo
16+
17+
Today, people who want to use C and Rust together in a project have to put
18+
substantial work into infrastructure or manual bindings. Whether by creating
19+
build system infrastructure to invoke bindgen/cbindgen (and requiring the
20+
installation of those tools), or manually writing C bindings in Rust, projects
21+
cannot simply drop Rust code into a C program or C code into a Rust program.
22+
This creates a high bar for adopting or experimenting with Rust, and makes it
23+
more difficult to provide Rust bindings for a C library.
24+
25+
By contrast, dropping C++ code into a C project or C code into a C++ project is
26+
trivial. The same compiler understands both C and C++, and allows compiling
27+
both together or separately. The developer does not need to duplicate
28+
declarations for the two languages, and can freely call between functions in
29+
both languages.
30+
31+
C and C++ are still not the same language. They have different idioms and
32+
common types, and a C interface may not be the most ergonomic to use from C++.
33+
Using C++ from C involves treating the C as C++, such that it no longer works
34+
with a C compiler that has no C++ support. But nonetheless, C++ and C integrate
35+
extremely well, and C++ is currently the easiest language to integrate into an
36+
established C project.
37+
38+
This is the level of integration we should aspire to for Rust and C.
39+
40+
### The next few steps
41+
42+
To provide seamless integration between Rust and C, we need a single compiler
43+
to understand both Rust and C. Thus, the first step will be to integrate a C
44+
preprocessor and compiler frontend into the Rust compiler. For at least the
45+
initial experimentation, we could integrate components from LLVM, taking
46+
inspiration from `zig cc`. (In the future, we can consider other alternatives,
47+
including a native Rust implementation. We could also consider components from
48+
c2rust or similar.)
49+
50+
We can either generate MIR directly from C (which would be experimental and
51+
incomplete but integrate better with the compiler), or bypass MIR and generate
52+
LLVM bytecode (which would be simpler but less well integrated).
53+
54+
This first step would provide substantial benefits already: a C compiler that's
55+
always available on any system with Rust installed, that generates code for any
56+
supported Rust target, and that always supports cross-language optimization.
57+
58+
We can further improve support for calling C from Rust. We can support
59+
"importing" C header files, to permit using this support to call external
60+
libraries, and to support inline functions.
61+
62+
### The "shiny future" we are working towards
63+
64+
Once C support is integrated, we can generate type information for C functions
65+
as if they were unsafe Rust functions, and then support treating the C code as
66+
a Rust module, adding the ability to import and call C functions from Rust.
67+
This would not necessarily even require header files, making it even simpler to
68+
use C from Rust. The initial support can be incomplete, supporting the subset
69+
of C that has reasonable semantics in Rust.
70+
71+
We will also want to add C features that are missing in Rust, to allow Rust to
72+
call any supported C code.
73+
74+
Once we have a C compiler integrated into Rust, we can incrementally add C
75+
extensions to support using Rust from C. For instance:
76+
- Support importing Rust modules and calling `extern "C"` functions from
77+
them, without requiring a C header file.
78+
- Support using `::` for scoping names.
79+
- Support simple Rust types (e.g. `Option` and `Result`).
80+
- Support calling Rust methods on objects.
81+
- Allow annotating C functions with Rust-enhanced type signatures, such as
82+
marking them as safe, using Rust references for pointer parameters, or
83+
providing simple lifetime information.
84+
85+
We can support mixing Rust and C in a source file, to simplify incremental
86+
porting even further.
87+
88+
To provide simpler integration into C build systems, we can accept a
89+
C-compiler-compatible command line (`CFLAGS`), and apply that to the C code we
90+
process.
91+
92+
We can also provide a CLI entry point that's sufficiently command-line
93+
compatible to allow using it as `CC` in a C project.
94+
95+
## Design axioms
96+
97+
- **C code should feel like just another Rust module.** Integrating C code into
98+
a Rust project, or Rust code into a C project, should be trivial; it should
99+
be just as easy as integrating C with C++.
100+
101+
- **This is not primarily about providing *safe* bindings.** This project will
102+
primarily make it much easier to access C bindings as unsafe interfaces.
103+
There will still be value in wrapping these unsafe C interfaces with safer
104+
Rust interfaces.
105+
106+
- **Calling C from Rust should not require writing duplicate information in Rust**
107+
that's already present in a C header or source file.
108+
109+
- **Integrating C with Rust should not require third-party tools**.
110+
111+
- **Compiling C code should not require substantially changing the information
112+
normally passed to a C compiler** (e.g. compiler arguments).
113+
114+
## Ownership and other resources
115+
116+
**Owner:** TODO
117+
118+
### Support needed from the project
119+
120+
* Lang team:
121+
* Design meetings to discuss design changes
122+
* RFC reviews
123+
* Compiler team:
124+
* RFC review
125+
126+
## Outputs and milestones
127+
128+
### Outputs
129+
130+
The initial output will be a pair of RFCs: one for an experimental integration of a C compiler into rustc, and the other for minimal language features to take advantage of that.
131+
132+
### Milestones
133+
134+
- Compiler RFC: Integrated C compiler
135+
- Lang RFC: Rust language support for seamless C integration
136+
137+
## Frequently asked questions

src/2024h2/slate.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ None
3131
|[Fallible allocation][] | ![Owner needed][own] | |
3232
| [Polonius on nightly][] | [lqd] | [Lang], [Types] |
3333
| [Impl trait everywhere][] | [oli-obk] | [Lang], [Types] |
34+
| [Seamless C Support][] | ![Owner needed][own] | [Lang] |
35+
| [Relaxing the Orphan Rule][] | ![Owner needed][own] | [Lang] |
3436

3537
## Not accepted goals
3638

@@ -48,6 +50,8 @@ None.
4850
[Return type notation]: ./Async--AsyncClosures.md
4951
[Polonius on nightly]: ./Polonius.md
5052
[Impl trait everywhere]: ./Impl-trait-everywhere.md
53+
[Seamless C Support]: ./Seamless-C-Support.md
54+
[Relaxing the Orphan Rule]: ./Relaxing-the-Orphan-Rule.md
5155

5256
[own]: https://img.shields.io/badge/Owned%20Needed-blue
5357

@@ -60,4 +64,4 @@ None.
6064
[LC]: https://www.rust-lang.org/governance/teams/leadership-council
6165
[Lang]: https://www.rust-lang.org/governance/teams/lang
6266
[Types]: https://www.rust-lang.org/governance/teams/compiler#team-types
63-
[Libs-API]: https://www.rust-lang.org/governance/teams/library#team-libs-api
67+
[Libs-API]: https://www.rust-lang.org/governance/teams/library#team-libs-api

0 commit comments

Comments
 (0)