Manish Goregaokar, a Rust and Unicode contributor, writes about Rust internals, garbage collection designs, and text encoding.
Commenters link his posts on garbage collectors in Rust and Unicode code points as wonderful, and use them to explain text handling.
>First, we'd love it if you would try our early container prototype on your build. Contact us and we'll add you to our closed alpha test.
If the code is available; sure. If it's not then sadly this isn't interesting.
>Also, we can send you the full paper (preprint) on the Debian case study, with the gory details.
This would be more interesting as I'm doing a master thesis regarding reproducible builds and rebuilders for debian at this moment, along with contributing to the effort in general. Feel free to send a copy to morten@linderud.pw
>The compiler can inject malware when it recognizes that its compiling itself, but we run arbitrary build systems, compiler tool chains, JITs.
The compiler can inject anny backdoor into any code as long as its invoked. We are not strictly limited to it compiling itself. I'm unsure how appealing to the diversity of the things you compile is an argument. A lot of things utilize `ld`, `gcc` or `tar` somewhere in their build chain regardless of what they build. It's not going to be harder to backdoor something if you have enough diversity.
This is a neat example of the possibilities you have with the rust compiler as an example:
https://manishearth.github.io/blog/2016/12/02/reflections-on-rusting-trust/
>The DRB website lists a Ph.D. dissertation on improving this situation, but I haven't read it, and I don't think it's been implemented in DRB
Davids PhD hasn't really been implemented to any large extent in the real-world, beside smaller…
The borrow checker allows for one mutable reference, or multiple immutable references. There are also primitives for allowing interior mutability through shared references, which enforce single access at a time by other means (mutexes, copying data in and out, etc).
References are always guaranteed to point to something that lives longer than them. What they refer to could either be on the stack, or it can be allocated and deallocated on the heap via smart pointers. Box<T> is similar to C++'s unique_ptr; there is a single owner, and when that owner is dropped, the referenced value is dropped. Arc<T> is similar to C++'s shared_ptr; it's an atomically reference counted pointer, so the value will be deallocated when the last clone is deleted.
These combine in ways that allow you to use most of those "best practice" patterns from C and C++, but with actual language guarantees that you will follow them and the compiler will catch it if you don't. In the internals of data structure implementation, you may need to go beyond what this allows with use of unsafe, but you can limit that just to a few small critical pieces of code that can be more thoroughly audited and tested.
In a large project "try to avoid doing that" doesn't really fly; in a large codebase, with dozens of developers, developed over multiple years, people are going to make mistakes. They will need to do some kind of refactoring, and one of the guarantees will get missed.
If you've done a decent amount of work in…
Out of the box, Rust encourages almost everything to be stack allocated, imposes a read-write lock on every value (i.e., you can have multiple immutable readers, but only one mutable writer at a time), and uses move semantics for variable assignments (i.e., values aren't copied but rather ownership of the value changes from one variable to some other variable).
Sometimes you need to drop one or several of these properties. It's very easy to do that -- Rust just makes you be explicit about it. If you want something to be heap allocated, you can use a Box/Rc/etc. If you want a value shared among multiple writers, there are several options; a common one is Arc<Mutex<T>>, which is also thread-safe. If you don't want move semantics, you can just copy the value using .clone().
A few lessons to take away, though:
* Because of that read/write lock I mentioned, it follows that you generally want to avoid taking a mutable reference to an entire data structure, because doing so effectively puts that writer lock on the whole thing. If you can take a mutable reference only to the piece you actually care about, that can help out a lot in some cases.
* Rust makes you feel like you should never clone, but really it's up to you. Exercise basic judgment that you'd use in any other language, and don't let perfect be the enemy of the good. In many cases it's probably not nearly as expensive as you might feel it is, and sometimes it'll just be optimized away in the end anyway.
* Try to…
It's both faster and you have more control over it; the two are linked in this case. This system lets the compiler do the hard work to figure out when it's ok to deallocate some piece of memory, unlike a GC, which figures it out at runtime. One you've determined that some memory can be deallocated, the actual process is very quick, usually just updating a list of free blocks in the memory allocator and maybe some statistics.
Rust does also support reference counting when you want it, which can bring its own set of performance issues in certain circumstances. Think more about general slowness due to constantly incrementing and decrementing references in an atomic fashion when you pass RC-ed data between functions, rather than the pauses seen with garbage collection. But how bad that is depends greatly on how and where you're using reference counted variables, and the addition of the lifetime/borrow system makes it easier to avoid some of the more egregious cases here.
Additionally, some people are doing work on GCs that work with Rust. The two links below have some good descriptions of the progress and challenges related to that.
http://blog.pnkfx.org/blog/2015/10/27/gc-and-rust-part-0-how-does-gc-work/
http://manishearth.github.io/blog/2015/09/01/designing-a-gc-in-rust/
Reference counting is a type of GC [0]. Just not a very good one in many cases.
I think it's a fair assumption to say that the author is aware of what Arcs are and how they work. I believe their point is more so that because of how async works in Rust, users have to reach for Arc over normal RAII far more often than in sync code. So at a certain point, if you have a program where 90% of objects are refcounted, you might as well use a tracing GC and not have the overhead of many small heap allocations/frees plus atomic ops.
Perhaps there are in fact ways around Arc-ing things for the author's use cases. But in my (limited) experience with Rust async I've definitely run into things like this, and plenty of example code out there seems to do the same thing [1].
For what it's worth, I've definitely wondered whether a real tracing GC (e.g. [2]) could meaningfully speed up many common async applications like HTTP servers. I'd assume that other async use cases like embedded state machines would likely have pretty different performance characteristics, though.
[0] https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)#Reference_counting
[1] https://tokio.rs/tokio/tutorial/shared-state
[2] https://manishearth.github.io/blog/2015/09/01/designing-a-gc-in-rust/
It’s worth noting, given the aspirational conclusion, that @T managed pointers were actually equivalent to Rc<T>, since they were only ever implemented with reference counting without cycle collection. (This would have changed had they stayed in the language, but winds changed instead.) The standard library doesn’t ship tracing GC, and it’s still not altogether clear how it would be best to do it. https://manishearth.github.io/blog/2021/04/05/a-tour-of-safe-tracing-gc-designs-in-rust/ is useful further reading. I think it’s fair to say that the “ship tracing GC as part of the standard library” ship has sailed, but power and convenience could still warrant language/standard library features to support it, though I doubt anything will ever happen, or at least in the next decade. The focus of the language shifted and was clarified quite a lot between the time of this article and even Rust 1.0 just under two years later.