Rc, a copy of std::rc that runs on stable Rust with weak references


#1

Since std::rc::Weak is unstable and doesn’t seem to be on the way to be stabilized, I just published https://crates.io/crates/rc. It’s a copy of the entire std::rc module with some features removed to make it work on stable Rust:

  • Unsized / dynamically-sized types T are not supported in Rc<T> or Weak<T>
  • #[unsafe_no_drop_flag] is not used, so (in curent Rust) Rc<T> and Weak<T> have a drop flag and are two words big (16 bytes 64-bit platforms) instead of one.
  • NonZero is not used, so Option<Rc<T>> and Option<Weak<T>> are one word bigger than Rc<T> or Weak<T> (for a total of 24 bytes instead of 8 on 64-bit platforms).
  • std::intrinsics::assume is not used, so the optimizer may not be able to remove as many redundant checks.

The memory usage increase can be significant (Kuchiki’s Node struct goes from 128 to 208 bytes), so I recommend using std::rc when possible. This is only a stop gap solution. In particular, if your own code is a library that other people might want to use in either nightly or stable Rust, I recommend something like this:

# Cargo.toml

[features]
unstable = []

[dependencies]
# Unfortunately, as of this writing, Cargo features can not *disable* dependencies.
# See https://github.com/rust-lang/cargo/issues/1839
rc = { version = "0.1.0" }
// lib.rs

#![cfg_attr(feature = "unstable", feature(rc_weak))]

#[cfg(not(feature = "unstable"))] extern crate rc;
#[cfg(feature = "unstable")] mod rc {
    pub use std::rc::*;
}
// some_module.rs

use rc::{Rc, Weak};

#2

I know people have been porting std modules to crates.io so they can be used in stable for a while, but I just dont get the reasoning.

Are they not unstable for a reason, and therefore should probably not be used in a stable distribution?

If you need Weak or other unstable features, why dont you just use unstable, and join the stabilization effort?


#3

Weak reference are not unstable because they are bad, only because we’re not 100% certain of the API or design yet. Rust makes very strong stability promises once something in std is marked #[stable], so this shouldn’t be done prematurely.

crates.io libraries on the other hand don’t need as much stability: they can be updated (or not) independently from Rust. If the std::rc API gets breaking changes and I update the rc crate accordingly, users can keep using older version of the crate. In fact, cargo update will automatically update from 0.1.0 to 0.1.x but not to 0.2.0.

I don’t have a problem using Nightly myself and keeping up with breaking changes. (I work on Servo, which possibly uses every unstable feature there is.) But when I publish libraries like Kuchiki for other people to use, I’d rather not force them to do the same.

Yes, it’s healthy to have a good number of users on Nightly to report breakage and other bugs, but it shouldn’t be what everyone has to use, or unstable features risk becoming de-facto stable before they’re ready. (See what happens with vendor prefixes for CSS properties on the web never being removed, and some non-WebKit engines implementing some -webkit-foo properties.)


#4

Yup, I get that it is unstable because it is unstable, and not going to be removed because it is bad. I was precisely wondering why you would want to do this because of the fact that the API can be changed at any time.

If the Weak API changes tomorrow, what will happen to this crate, is what I am asking, or any of the crates that mirror functionality, like syntex. Im guessing you just expect the users downstream to update their code, but then what is the point? The users chose stable because they did not want to have to change their code due to upstream changes.

It just feels like if they want this functionality, it should be in nightly, precisely because they want to use features that may not exist tomorrow.


#5

I think @SimonSapin explained what will happen:

This is one of the big advantages of having things in cargo instead of std: there can be more than one version of a thing.


#6

If std::rc::Weak changes I may or may not publish a new version of the rc crate. But either way, users who don’t feel like updating their code can still use the older version of the crate. If I pick a version number that is semver-incompatible (0.2.0 in this case), Cargo will not upgrade them automatically.

If std::rc::Weak is removed entirely, same story: the rc crate will still be there.