Trivia About Rust Types

Trivia About Rust Types: An (Authorized) Transcription of Jon Gjengset’s Twitter Thread.
Preface (by Jimmy Hartzell) I am a huge fan of Jon Gjengset’s Rust for Rustaceans, an excellent book to bridge the gap between beginner Rust programming skills and becoming a fully-functional member of the Rust community. He’s famous for his YouTube channel as well; I’ve heard good things about it (watching video instruction isn’t really my thing personally). I have also greatly enjoyed his Twitter feed, and especially have enjoyed the thread surrounding this tweet:

Read in full here:

This thread was posted by one of our members via one of our news source trackers.


Corresponding tweet for this thread:

Share link for this tweet.


Even T: 'static doesn’t imply owned — consider &'static str for example.

It doesn’t imply owned, it implies it itself isn’t referencing something that’s not also 'static internally (unless wrapped, which you don’t care about then).

Did you know that std::sync::mpsc has had a known bug since 2017, and that the implementation may actually be replaced entirely with the crossbeam channel implementation?

Yeah, seen this before as well, crossbeam is really well amde, and std::sync::mpsc honestly shouldn’t have been in std.

Did you know that even though we got u128 a long time ago now, we still don’t have repr(128)?

Yeah that’s bugged me before, it’s an LLVM limitation sadly (which is trying to be fixed though). The limitation exists because of C and C++ limitations though (blah!).

Did you know that Box<T> is a #[fundamental] type, which means that it’s exempt from the normal rules that don’t allow you to implement foreign traits for foreign types (assuming T is a local type)?

On another point too, the orphan rules are looking to be relaxed now that enough testing has been done! I hope it comes soon!

Did you know that std has three different ways to spawn a child process on Linux (posix_spawn, clone3/exec, fork/exec) depending on what capabilities your kernel version has?

Haven’t looked into how that is implemented, but it makes sense.

Did you know that Vec::swap_remove is way faster than Vec::remove if you can tolerate changes to ordering?

One of my favorite Vec functions! Did you also know that the ‘traditional’ term of an array of ‘stuff’ where you don’t care about the order is generally called a Bag in most texts? Vec::swap_remove is such a function for it to be a bag!

Did you know that until Rust 1.35, you couldn’t call a Box<dyn FnOnce> and needed a special type (FnBox) for it!

Huh, didn’t know about FnBox, interesting…

Did you know that in Rust 1.62 we’ll get a deterministic ordering function for floating point numbers?

Yep, but did you also know it can do some surprising orderings if the float isn’t properly normalized and such too (still deterministic though!).

Did you know that Any is really non-magical? It just has a blanket implementation for all T that returns TypeId::of::<T>(), and to downcast it simply compares the return value of that trait method to see if it’s safe to cast to downcast to a type!

Yep, Any casting is just a virtual function call and an integer comparison (maybe larger in the future). It is both slightly more costly and slightly cheaper than traditional OOP casting, depending on the circumstance, still cheap in any case though unless in a hard loop or things like that.

TypeId is magic though.

Very, and… I don’t like it… It’s basically a compile-time hash of the type. Collisions are possible (though very unlikely). I prefer the traditional C++ way of having basically this:

static int NEW_ID = 0;
template<typename T> struct TYPE_ID {
  static int TYPE_ID = NEW_ID++;

(In summary, there’s a bit more stuff around that but I’m trying to keep it conceptually simple).

But then you get a unique type integer for each type you call it with, generated by the compiler, and fully unique.

Hooooowever, there are issues with dynamic libraries (static is fine) and resolving those, which can be fixed by making a marshaling interface to get the ID’s from just one place, however that obviously has overhead then. Rust’s has the same issue too though.

We might be able to do the C++ way in Rust in the future, but honestly it’s unlikely as generating new statics into the program read only data structure has… issues on certain platforms (windows being one, what C++ is doing there is an incredibly bad hack that shouldn’t be done and does break at times).

If you want perfectly unique type ID’s, and of course you can define your own Any type with fully safe code, you’d instead want a procmacro in rust to save out the type and a new ID into a file to be looked up at compile time as needed. This would make looking up type ID’s at runtime instead of just compile time quite possible too though with a simple extension. And yes I have ran across procmacro libs to do this, lol.

Did you know that fn foo(self) is syntactic sugar for fn foo(self: Self), and that one day you’ll be able to use other types for self that involve Self, like fn foo(self: Arc<Self>)?

To be clear, right now you can use any type that has an AsRef<Self> implementation right now, other types that don’t have that implementation should be supported later.

Did you know that there used to also be a trait accompanying Wrapping, WrappingOps, that was removed last minute before 1.0?

Makes sense it seems, already implementations for all those otherwise.

Did you know that usize isn’t really “the size of a pointer”. Instead, it’s more like “the size of a pointer address difference”, and the two can be fairly different!

Yep! This is a big thing that a lot of languages get wrong, especially C and C++ (both of which are trying to fix it but can’t find a really good way that doesn’t break old code or make code much slower…).

Did you know that the whole c_void type is a collection of hacks to try to work around the lack for extern types?

Huh, a lot of considerations around that…

Did you know that the Rust devs are working on a “raw” entry API for HashMap that allows you to (unsafely) avoid re-hashing a key you’ve already hashed?

Ooo didn’t know this, nice!

Did you know that while &mut T is defined as meaning “mutable reference” in the Rust reference, you’re often better off thinking of it as “mutually exclusive reference”.

Yep, &mut T doesn’t mean it’s mutable, it means there is just one ‘alias’ of it available right now, which happens to be mutable. I wish those concepts were split into two things even if it would be slightly more verbose, but eh…

Did you know that until Rust 1.35.0, Box<T> where T: Fn did not impl Fn, so you couldn’t (easily) call boxed closures!

…this was mentioned near the top of the article though?

Overall good article, knew almost all of it though so inaccurate title of the original tweet that spawned it, lol.

1 Like