Imagine Rust's standard library could be shrunk down to its bare essentials; it contains only that which can't be implemented by third party crates using the stable compiler.
What would that look like? I believe it would have at least these modules:
- num (for
UnsafeCell. But I think I'm missing a lot of other essentials.
Rust provides a
core crate and an
Sure, but can't much of that be implemented by third party crates? For example
time doesn't do anything special, no? And for that matter is
alloc doing anything that a crate couldn't do?
I mean there are many types that are integrated into the compiler, e.g. the
IntoIterator trait is linked to for loops, even if you could otherwise implement it yourself.
Anything that's a
#[lang] item is closely tied to the compiler, like
core::fmt is tightly integrated with
Box allows moving the inner value out (
let a: Vec<u8> = *Box::new(vec!); is allowed, notice the
alloc also adds some methods to
str, which is normally not allowed as
str is not a type defined inside
alloc. Everything in
core::marker is special cased by the compiler.
core::arch is mostly implemented using LLVM intrinsics that are not accessible on stable.
core::future is used by
core::option must be in the standard library so that other standard library APIs can use them. For example,
Option is needed by the
Iterator trait. (Also, they need to implement the unstable
Try trait to support the
? operator, and unstable
Termination trait to support
fn main() -> Result.)
core::ops traits are all lang items to support operator overloading.
core::any relies on the unstable
core::pin::Pin is a lang item. (Is this needed for async/await? I'm not sure.)
core::clone::Clone is a lang item so that the
Copy trait can depend on it. Removing that relationship now would be a breaking change, though if it had been removed pre-1.0, I don't think it would cause any fundamental problems.
core::slice::from_raw_parts used to require unstable code to implement, but in Rust 1.42 and later it can be implemented in terms of
core::sync::atomic is implemented using unstable intrinsics.
At least some of
core::poll is needed for async/await.
Some core macros like
include! require compiler support.
libcore also contains inherent methods on built-in types, like
str::as_bytes, which use intrinsics or other unstable code.
Quite the opposite, it might be one of the more complex interfaces in terms of necessary maintenance. The
core crate has those parts of
time that are fully standalone and is hence very simple but also small: It has only a
Duration structure. This is because
std::time::Instant needs to interact with the clock source of the operating system, which means dealing with (non-)monotonicity, epochs, clock resolution. If you think time is simple, think again. Perhaps the easiest why to explain that it is hard is because time is not something Rust can influence or define like a memory model, it needs to conform to what is available while still providing the minimum for thread, scheduling etc. And the really complex stuff such as timezones is indeed not handled by the standard library but by crates such as
Additionally, unsizing coercions (e.g.
Box<dyn Trait>) require the unstable
CoerceUnsized trait, so all types that implement that trait (and any types that depend on those) must be in the standard library until it is stabilized. This includes
Some standard slice-like types like
OsStr are implemented using unstable assumptions that are not valid outside of the standard library. This might be fixable, though.
I think a lot of the panic-related code (
std::thread::panicking) relies on integration with the startup glue that is not accessible to external crates.
For sure, I didn't mean it wasn't a hard or complicated thing to do. I meant "special" in the sense it doesn't require compiler magic to implement so other crates can do the same job.
I believe that
core::time could all be implemented outside of the standard library, as long as other APIs that depend on them (like
Condvar::wait_timeout) were also moved to external crates.
std::env::args is integrated with the compiler-generated startup code, and could not easily be moved to an external crate. On at least some platforms, it could be implemented in some other way outside of libstd.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.