diff --git a/src/2024h2/Relaxing-the-Orphan-Rule.md b/src/2024h2/Relaxing-the-Orphan-Rule.md new file mode 100644 index 0000000..6839a51 --- /dev/null +++ b/src/2024h2/Relaxing-the-Orphan-Rule.md @@ -0,0 +1,132 @@ +# Relaxing the Orphan Rule + +| Metadata | | +| --- | --- | +| Owner(s) | | +| Teams | *lang* | +| Status | WIP | + +## Motivation + +Relax the orphan rule, in limited circumstances, to allow crates to provide +implementations of third-party traits for third-party types. The orphan rule +averts one potential source of conflicts between Rust crates, but its presence +also creates scaling issues in the Rust community: it prevents providing a +third-party library that integrates two other libraries with each other, and +instead requires convincing the author of one of the two libraries to add +(optional) support for the other, or requires using a newtype wrapper. Relaxing +the orphan rule, carefully, would make it easier to integrate libraries with +each other, share those integrations, and make it easier for new libraries to +garner support from the ecosystem. + +### The status quo + +Suppose a Rust developer wants to work with two libraries: `lib_a` providing +trait `TraitA`, and `lib_b` providing type `TypeB`. Due to the orphan rule, if +they want to use the two together, they have the following options: + +- Convince the maintainer of `lib_a` to provide `impl TraitA for TypeB`. This + typically involves an optional dependency on `lib_b`. This usually only + occurs if `lib_a` is substantially less popular than `lib_b`, or the + maintainer of `lib_a` is convinced that others are likely to want to use the + two together. This tends to feel "reversed" from the norm. + +- Convince the maintainer of `lib_b` to provide `impl TraitA for TypeB`. This + typically involves an optional dependency on `lib_a`. This is only likely to + occur if `lib_a` is popular, and the maintainer of `lib_b` is convinced that + others may want to use the two together. The difficulty in advocating this, + scaled across the community, is one big reason why it's difficult to build + new popular crates built around traits (e.g. competing + serialization/deserialization libraries, or competing async I/O traits). + +- Vendor either `lib_a` or `lib_b` into their own project. This is + inconvenient, adds maintenance costs, and isn't typically an option for + public projects intended for others to use. + +- Create a newtype wrapper around `TypeB`, and implement `TraitA` for the + wrapper type. This is less convenient, propagates throughout the crate (and + through other crates if doing this in a library), and may require additional + trait implementations for the wrapper that `TypeB` already implemented. + +All of these solutions are suboptimal in some way, and inconvenient. In +particular, all of them are much more difficult than actually writing the trait +impl. All of them tend to take longer, as well, slowing down whatever goal +depended on having the trait impl. + +### The next few steps + +As an initial experiment, try relaxing the orphan rule for binary crates, since +this cannot create library incompatibilities in the ecosystem. Allow binary +crates to implement third-party traits for third-party types, possibly +requiring a marker on either the trait or type or both. See how well this works +for users. + +As a second experiment, try allowing library crates to provide third-party +impls as long as no implementations actually conflict. Perhaps require marking +traits and/or types that permit third-party impls, to ensure that crates can +always implement traits for their own types. + +### The "shiny future" we are working towards + +Long-term, we'll want a way to resolve conflicts between third-party trait +impls. + +We should support a "standalone derive" mechanism, to derive a trait for a type +without attaching the derive to the type definition. We could save a simple +form of type information about a type, and define a standalone deriving +mechanism that consumes exclusively that information. + +Given such a mechanism, we could then permit any crate to invoke the standalone +derive mechanism for a trait and type, and allow identical derivations no +matter where they appear in the dependency tree. + +## Design axioms + +- **Rustaceans should be able to easily integrate a third-party trait with a + third-party type without requiring the cooperation of third-party crate + maintainers.** + +- **It should be possible to *publish* such integration as a new crate.** For + instance, it should be possible to publish an `a_b` crate integrating `a` + with `b`. This makes it easier to scale the ecosystem and get adoption for + new libraries. + +- **Crate authors should have some control over whether their types have + third-party traits implemented.** This ensures that it isn't a breaking + change to introdice first-party trait implementations. + +[da]: ../about/design_axioms.md + +## Ownership and other resources + +**Owner:** TODO + +### Support needed from the project + +* Lang team: + * Design meetings to discuss design changes + * RFC reviews +* Blog post inviting testing, evaluation, and feedback + +## Outputs and milestones + +### Outputs + +The output will be a pair of RFCs: +- A lang RFC proposing a very simple system for binaries to ignore the orphan rule. +- A lang RFC proposing a system with more careful safeguards, to relax the orphan rule for publishable library crates. + +### Milestones + +- Accepted RFCs. + +## Frequently asked questions + +### Won't this create incompatibilities between libraries that implement the same trait for the same type? + +Yes! The orphan rule is a tradeoff. It was established to avert one source of +potential incompatibility between library crates, in order to help the +ecosystem grow, scale, and avoid conflicts. However, the presence of the orphan +rule creates a different set of scaling issues and conflicts. This project goal +proposes to adjust the balance, attempting to achieve some of the benefits of +both. diff --git a/src/2024h2/Seamless-C-Support.md b/src/2024h2/Seamless-C-Support.md new file mode 100644 index 0000000..69147c1 --- /dev/null +++ b/src/2024h2/Seamless-C-Support.md @@ -0,0 +1,137 @@ +# Seamless C support + +| Metadata | | +| --- | --- | +| Owner(s) | *Github usernames or other identifying info for goal owners* | +| Teams | *Names of teams being asked to commit to the goal* | +| Status | WIP | + +## Motivation + +Using C from Rust should be as easy as using C from C++: completely seamless, +as though it's just another module of code. You should be able to drop Rust +code into a C project and start compiling and using it in minutes. + +### The status quo + +Today, people who want to use C and Rust together in a project have to put +substantial work into infrastructure or manual bindings. Whether by creating +build system infrastructure to invoke bindgen/cbindgen (and requiring the +installation of those tools), or manually writing C bindings in Rust, projects +cannot simply drop Rust code into a C program or C code into a Rust program. +This creates a high bar for adopting or experimenting with Rust, and makes it +more difficult to provide Rust bindings for a C library. + +By contrast, dropping C++ code into a C project or C code into a C++ project is +trivial. The same compiler understands both C and C++, and allows compiling +both together or separately. The developer does not need to duplicate +declarations for the two languages, and can freely call between functions in +both languages. + +C and C++ are still not the same language. They have different idioms and +common types, and a C interface may not be the most ergonomic to use from C++. +Using C++ from C involves treating the C as C++, such that it no longer works +with a C compiler that has no C++ support. But nonetheless, C++ and C integrate +extremely well, and C++ is currently the easiest language to integrate into an +established C project. + +This is the level of integration we should aspire to for Rust and C. + +### The next few steps + +To provide seamless integration between Rust and C, we need a single compiler +to understand both Rust and C. Thus, the first step will be to integrate a C +preprocessor and compiler frontend into the Rust compiler. For at least the +initial experimentation, we could integrate components from LLVM, taking +inspiration from `zig cc`. (In the future, we can consider other alternatives, +including a native Rust implementation. We could also consider components from +c2rust or similar.) + +We can either generate MIR directly from C (which would be experimental and +incomplete but integrate better with the compiler), or bypass MIR and generate +LLVM bytecode (which would be simpler but less well integrated). + +This first step would provide substantial benefits already: a C compiler that's +always available on any system with Rust installed, that generates code for any +supported Rust target, and that always supports cross-language optimization. + +We can further improve support for calling C from Rust. We can support +"importing" C header files, to permit using this support to call external +libraries, and to support inline functions. + +### The "shiny future" we are working towards + +Once C support is integrated, we can generate type information for C functions +as if they were unsafe Rust functions, and then support treating the C code as +a Rust module, adding the ability to import and call C functions from Rust. +This would not necessarily even require header files, making it even simpler to +use C from Rust. The initial support can be incomplete, supporting the subset +of C that has reasonable semantics in Rust. + +We will also want to add C features that are missing in Rust, to allow Rust to +call any supported C code. + +Once we have a C compiler integrated into Rust, we can incrementally add C +extensions to support using Rust from C. For instance: +- Support importing Rust modules and calling `extern "C"` functions from + them, without requiring a C header file. +- Support using `::` for scoping names. +- Support simple Rust types (e.g. `Option` and `Result`). +- Support calling Rust methods on objects. +- Allow annotating C functions with Rust-enhanced type signatures, such as + marking them as safe, using Rust references for pointer parameters, or + providing simple lifetime information. + +We can support mixing Rust and C in a source file, to simplify incremental +porting even further. + +To provide simpler integration into C build systems, we can accept a +C-compiler-compatible command line (`CFLAGS`), and apply that to the C code we +process. + +We can also provide a CLI entry point that's sufficiently command-line +compatible to allow using it as `CC` in a C project. + +## Design axioms + +- **C code should feel like just another Rust module.** Integrating C code into + a Rust project, or Rust code into a C project, should be trivial; it should + be just as easy as integrating C with C++. + +- **This is not primarily about providing *safe* bindings.** This project will + primarily make it much easier to access C bindings as unsafe interfaces. + There will still be value in wrapping these unsafe C interfaces with safer + Rust interfaces. + +- **Calling C from Rust should not require writing duplicate information in Rust** + that's already present in a C header or source file. + +- **Integrating C with Rust should not require third-party tools**. + +- **Compiling C code should not require substantially changing the information + normally passed to a C compiler** (e.g. compiler arguments). + +## Ownership and other resources + +**Owner:** TODO + +### Support needed from the project + +* Lang team: + * Design meetings to discuss design changes + * RFC reviews +* Compiler team: + * RFC review + +## Outputs and milestones + +### Outputs + +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. + +### Milestones + +- Compiler RFC: Integrated C compiler +- Lang RFC: Rust language support for seamless C integration + +## Frequently asked questions diff --git a/src/2024h2/slate.md b/src/2024h2/slate.md index 8859486..3aa8781 100644 --- a/src/2024h2/slate.md +++ b/src/2024h2/slate.md @@ -31,6 +31,8 @@ None | ↳ [Fallible allocation][] | ![Owner needed][own] | | | [Polonius on nightly][] | [lqd] | [Lang], [Types] | | [Impl trait everywhere][] | [oli-obk] | [Lang], [Types] | +| [Seamless C Support][] | ![Owner needed][own] | [Lang] | +| [Relaxing the Orphan Rule][] | ![Owner needed][own] | [Lang] | ## Not accepted goals @@ -47,6 +49,8 @@ None. [Fallible allocation]: ./Fallible-allocation.md [Polonius on nightly]: ./Polonius.md [Impl trait everywhere]: ./Impl-trait-everywhere.md +[Seamless C Support]: ./Seamless-C-Support.md +[Relaxing the Orphan Rule]: ./Relaxing-the-Orphan-Rule.md [own]: https://img.shields.io/badge/Owned%20Needed-blue @@ -59,4 +63,4 @@ None. [LC]: https://www.rust-lang.org/governance/teams/leadership-council [Lang]: https://www.rust-lang.org/governance/teams/lang [Types]: https://www.rust-lang.org/governance/teams/compiler#team-types -[Libs-API]: https://www.rust-lang.org/governance/teams/library#team-libs-api \ No newline at end of file +[Libs-API]: https://www.rust-lang.org/governance/teams/library#team-libs-api