A
Alexis Beingessner
cglab.ca/~abeinges · Personal blog · on HN since 2014
Alexis Beingessner, a Rust contributor, writes about Rust data structures, collections, and language design.
What HN saysHN commenters praise his "Learning Rust With Entirely Too Many Linked Lists" as one of the best explorations of any language and for learning data structures in Rust.
61HN people shared it
42linked it in comments
26stories submitted
713story points
2 years agolast shared
2014people per year2026
Most-shared posts
- 1Learning Rust with Entirely Too Many Linked Lists26 people · 28 points · first shared 2015 · 1 comments on HN
- 2Pre-Pooping Your Pants with Rust11 people · 131 points · first shared 2015 · 97 comments on HN
- 3Rust Collections Case Study: BTreeMap (2015)9 people · 79 points · first shared 2015 · 3 comments on HN
- 4Learning Rust with Entirely Too Many Linked Lists8 people · 89 points · first shared 2015 · 37 comments on HN
- 5Hash rs4 people · first shared 2015
- 6Building a HashMap in Rust – Part 1: What's a HashMap?3 people · 6 points · first shared 2015 · 3 comments on HN
- 7The Many Kinds of Code Reuse in Rust3 people · 5 points · first shared 2016 · discussion on HN
- 8Rust, Generics, and Collections1 people · 187 points · first shared 2014 · 10 comments on HN
- 9Rust, Lifetimes, and Collections1 people · 99 points · first shared 2014 · 45 comments on HN
- 10Unsafe Rust: An Intro and Open Questions1 people · 86 points · first shared 2015 · 32 comments on HN
- 11Learning Rust with Entirely Too Many Linked Lists1 people · 3 points · first shared 2015 · discussion on HN
- 12Vec1 people · first shared 2015
- 13Everyone peaches1 people · first shared 2015
What HN people wrote when they linked it
speed_spread · 2022-11-26
It's not _really_ a tutorial. But it's one of the best exploration of any language I've read.
https://cglab.ca/~abeinges/blah/too-many-lists/book/README.html
richardwhiuk · 2018-10-09
A Rc cycle causing a leak.
See the very excellent http://cglab.ca/~abeinges/blah/everyone-poops/
Too · 2017-04-24
"Learning Rust With Entirely Too Many Linked Lists" is a great example of the complications you run into writing such a data structure: http://cglab.ca/~abeinges/blah/too-many-lists/book/
nebopolis · 2017-01-24
Learning Rust With Entirely Too Many Linked Lists (http://cglab.ca/~abeinges/blah/too-many-lists/book/) is the best resource I've found for learning how to create data structures in Rust. It goes over a lot of the pain points of interacting with cyclic data structures.
caconym_ · 2017-01-15
I think it took me a couple of weeks to be able to write practical programs (i.e. actual useful things) and a month or two more to feel really comfortable with it. I was not pursuing it on anything close to a full-time basis. I recommend this tutorial:
http://cglab.ca/~abeinges/blah/too-many-lists/book/
for helping to grok the memory model. I tried to implement each chapter's data structure before I read the chapter so that I would really understand what problem the introduced memory constructs were solving.
It's definitely not an easy language to learn, but once you get past the memory model stuff I think the learning curve at least gets a little flatter.
MichaelGG · 2016-08-04
Great article.
1. This seems to disagree with Rust's tests for FVN vs xxHash.[1] This article has xxHash winning a bit after 10 bytes. The Rust one has FVN winning until after 32 bytes. Rust recently added FVN. Is someone wrong or am I missing something?
2. Why is 64-bit slower on asm.js? If the host is 64-bit shouldn't it get 64-bit? I know JS doesn't have proper ints, but I thought asm.js-aware browsers were supposed to handle this well?
Curious: Is there no uniform, fast, way to switch the algorithm for small inputs? Require the caller to hint that the key might be small (<8 or 16 bytes), otherwise in streaming mode, just restart if it turns out you only get <16 bytes. Or will that branching+code kill the gain?
1: http://cglab.ca/~abeinges/blah/hash-rs/
Gankro · 2015-11-21
I've literally never heard of Vhash, and I see no references to it outside of the 2007 paper. As far as I know, the state of the art for "fast and secure" is still SipHash 2-4 or 2-3.
While SipHash perf is generally quite good, it's still not as fast as Fnv on small inputs or XxHash on large inputs. As in, 4x slower [0]. FarmHash has great perf if you can invoke it in the way it wants, but doesn't do well in a streaming context.
[0]: http://cglab.ca/~abeinges/blah/hash-rs/
hansvm · 2024-10-18
> Wait, when exactly did the soundness rules change since 1.0? When have you had to re-audit unsafe code?
At a minimum you have to check that the rules haven't changed for each version [0].
The issue with destructors just before 1.0 dropped [1] would have been something to scrutinize pretty closely. I'm not aware of any major changes since then which would affect previously audited code, but new code for new Rust versions (e.g., when SIMD stabilized) needs to be considered with new rules as well.
> none of that changed to my knowledge
This is perhaps a bit pedantic, but the nomicon has bug fixes all the time (though the underlying UB scenarios in the compiler remain stable), and it's definitely worth re-examining your unsafe Rust when you see changes which might have incorrectly led a programmer to write some UB.
[0] https://doc.rust-lang.org/reference/behavior-considered-undefined.html [1] https://cglab.ca/~abeinges/blah/everyone-poops/
SMFloris · 2021-04-30
Recently experimented a bit with Rust and I found the reverse to be true. You cannot compose types in Rust. You compose behaviors not types. Very important distinction as I found out the hard way.
Take the following example I have found on the net: https://play.rust-lang.org/?version=stable&mode=debug&edition=…
In that example, both the bicycle and the car have the property `speed`. Imagine you have multiple types now that need to have the `speed` property. You would need to copy-paste the same code for each new type in order for you to be type safe.
Apparently it is called *Monomorphization*: https://cglab.ca/~abeinges/blah/rust-reuse-and-recycle/#monomorphizati…
From the article:
* But if I want a single queue to be able to handle different tasks, then it's not clear how that could be done with monomorphization alone. That's why it's called "mono"morphization. It's all about taking abstract implementations and creating instances that do one thing. *
Which was exactly what I was experimenting with: A single queue worker that can handle different cases. Honestly, it made Rust almost not worth it for me. Sadly, I was too deep to turn back so I wound up doing the whole thing in Rust. I have tons of copy-paste code. It is ugly and it is bothering me.
nickpsecurity · 2019-01-07
An article you might find helpful is this one on why imperative algorithms are harder to mathematically verify than functional ones:
https://semantic-domain.blogspot.com/2018/04/are-functional-programs-e…
You don't need to be a mathematician to follow it with this excerpt summarizing its key point:
"The difficulty of imperative programming arises from the combination of state, aliasing and procedure calls. Any two of these features can be handled without that much difficulty, but the combination of all three effectively makes reasoning (nearly) as difficult as correct concurrent programming. "
The garbage-collected languages let you ignore the aliasing problems with a performance penalty. Rust in safe mode without GC forces you to (a) deal with it and (b) deal with it in a way that works for all inputs (type/memory safety). That usually requires mathematical verification using tools such as separation logic. Rust's method is much easier to use with tradeoff of limitations on expressing code in certain ways.
Folks that get along with the borrow-checker say it helps to design the program around data and easy methods of using it versus starting with control flow forcing it on a data structure. I'll also add that linked lists are inherently hard to get right on all inputs regardless of low-level language. They're actually a popular way to test new, mathematical methods for specifying and proving algorithms correct. Fortunately, Rust folks have a goto write-up on…
ekidd · 2018-06-09
> I'd like to hear something like "This is how our team used Rust to do (really hard thing involving heavy concurrency and lots of state)".
Our team uses Rust for moderately complex concurrency.
TL;dr: There are tradeoffs, but Rust can be quite nice when you care about performance.
In my experience, concurrency is actually pleasant in Rust. The borrow checker eliminates 99% of problems before they ever occur. As for libraries, the popular crossbeam library provides scoped thread pools, which make it easy to spin up a bunch of local worker threads. https://docs.rs/crossbeam/0.3.2/crossbeam/struct.Scope.html#method.spa… For "parallel iterators", Rayon is excellent. https://github.com/rayon-rs/rayon For async I/O, the tokio library still demands solid Rust skills (at least until Rust 2018 lands), but once you figure it out, it Just Works. https://tokio.rs/
As for our other experiences using Rust:
- Rust is amazing for fast, cross-platform CLI tools.
- For most kinds of programs, I barely notice the borrow checker any more. But this is partly because I don't write programs with giant webs of objects that all try to mutate each other (like some game engines, for example). Also, I've never needed to implement a non-hierarchical data structure in Rust (the gory details of which are described at http://cglab.ca/~abeinges/blah/too-many-lists/book/), mostly because anything I needed was already on crates.io.
- Library support is much better than I would expect for a young…
bascule · 2017-04-02
I can't tell if this is an April Fool's joke or not. If it is, congratulations, troll successful. But I'm going to go ahead and reply anyway...
There are exactly two valid* points in this post:
- rustc is slow
- "the circlejerk"
* i.e. not completely without merit
I'll just go through these really quick:
1. rustc is slow
Rust just shipped (in beta) incremental compilation, a technique commonly used by compilers to speed up recompiles:
https://internals.rust-lang.org/t/incremental-compilation-beta/4721
This doesn't change the fact rustc is slow, but it certainly makes the developer experience much better. Try it out!
That said, rustc is still slow. A valid complaint.
2. rust needs unions
Rust has two types of unions:
- tagged unions a.k.a. sum types. These are preferred
- #[feature(untagged_unions)]: actual C-style unions, unsafe, useful for C interop
You probably want the first kind. Rust does have them!
3. linked lists are great
Linked lists are great! I use them in one of the main Rust programs I'm working on. The thing about Rust linked lists is how you write one will depend entirely on your memory model.
One of the best tutorials on Rust explains the language's memory model in terms of linked lists. It's a great read, a harrowing tale of "fighting rustc" until you achieve victory:
http://cglab.ca/~abeinges/blah/too-many-lists/book/
I'm using immutable arena-allocated linked lists, which is a great pattern. This is in conjunction with…
kibwen · 2017-02-17
> For people like me, if writing trivial data-structures in Rust is a great challenge, it shows that writing other, less trivial things in Rust will be much more challenging than might be preferred.
I understand the source of the sentiment, but also disagree with it. I've been writing Rust code for years and have never had occasion to write my own custom data structure, and (discounting FFI) I've reached for the `unsafe` keyword like twice (which I think I ended up removing anyway, because I was trying to be too clever).
But then again, my background is in higher-level languages (Java, Python) where writing data structures isn't your usual beginner task. I sympathize with C programmers to whom a linked list is the go-to toy learning program, but the urge to resort to unsafe shenanigans to implement self-referential data structures doesn't reflect the typical experience of using the language.
And for those who still wish to persist, may I recommend the book "Learning Rust With Entirely Too Many Linked Lists": http://cglab.ca/~abeinges/blah/too-many-lists/book/
Manishearth · 2017-02-09
> It was a weekend learning project, and all I wanted to do was create a freshman level data structure from scratch.
It's worth mentioning that the implementation difficulty of data structures in Rust is not representative of the general difficulty of programming in Rust. Just because this is hard doesn't make it a bad language. Rust's philosophy is that you deal with the trouble of writing unsafe code each time you need a new low level abstraction, and when done, you don't have to worry about it again.
Also, writing generic datastructures in C++ without falling afoul of UB, and/or getting destruction semantics right can be quite tricky. Rust ... really doesn't have additional issues here; raw pointers in Rust work the same way as in C++, except they're a tad verbose. The only difference is that in Rust you probably want to provide a safe API, whereas in "freshman C++ datastructures" the datastructure does not have the unsafety neatly encapsulated. This is a hard task in both Rust and C++, especially with generic datastructures.
Writing datastructures isn't really a common task. It's a "simple" task because it's simple in C and C++, but here's no real reason it has to be in Rust. You can write inefficient datastructures in 100% safe Rust without too many problems, much like you can implement datastructures in regular-joe Java. Writing efficient, low-level datastructures can be pretty hard, but like I said it's a rare task so not much of an…
the_mitsuhiko · 2024-12-16
The pattern that this relies on is called "pre-pooping" because of this blog post: https://cglab.ca/~abeinges/blah/everyone-poops/
raybb · 2024-08-29
Link for those who also would have to look it up https://cglab.ca/~abeinges/blah/everyone-poops/
SkiFire13 · 2023-09-08
> I don’t see why it would be an either/or. For instance, Rc does not leak memory, and neither do many cases of interior mutability.
`Rc` and internal mutability together do allow creating cycles and thus leaking with only safe code. I suggest you to read https://cglab.ca/~abeinges/blah/everyone-poops/ if you haven't done already, it explains the historical reasons for why `std::mem::forget` was changed to be safe.
> Edit 2: maybe an auto trait could statically disallow Rc cycles somehow?
It could be done with an auto and implied trait that is implemented in the opposite case (the type can be safely leaked), but then all the ecosystem must be changed to use `?Leakable` and it would be a pain.
littlestymaar · 2021-03-10
Rust implements affine types, which means every object must be used at most once. You cannot use them twice, but you can discard them and not do anything with them. Linear types means exactly once.
but I don't think you can easily move from affine types to linear types in the case of Rust, see leakpocalypse[1]
[1]: https://cglab.ca/~abeinges/blah/everyone-poops/#leakpocalypse
pdpi · 2019-04-11
Not sure if there was nothing post-1.0, but this[0] particular mess was just before the 1.0 release and, at the time, caused a fair bit of chaos.
0. http://cglab.ca/~abeinges/blah/everyone-poops/
chug · 2019-01-11
I came across this last night (http://dtrace.org/blogs/bmc/2018/09/28/the-relative-performance-of-c-a… and went down the rabbit hole of Rust and its BTreeSet (http://cglab.ca/~abeinges/blah/rust-btree-case/). They came to a very similar conclusion. It all makes me wonder if there's low hanging fruit in a lot of languages/libraries to simply swap out red black trees for B-trees (though I'm guessing the higher constant time cost of B-trees would make it necessary to swap between tree implementations for a truly general case).
wscott · 2018-11-30
I have heard this is a really good resource for understanding this exact aspect of Rust
http://cglab.ca/~abeinges/blah/too-many-lists/book/
urschrei · 2018-03-30
The difficulty of writing self-referential data structures in Rust arises on HN often. Every time, the answer is, broadly, the same:
- It is certainly difficult
- Strategies and approaches from low-level languages which are at least cosmetically similar will probably be unavailing
- In some (many?) cases, crates (Rental, Petgraph, Spade) exist that already implement them. Their design can be studied
- There's an entire book (http://cglab.ca/~abeinges/blah/too-many-lists/book/) devoted to writing linked lists in Rust. It's highly informative
Without wishing to explicitly criticise your approach to learning Rust, I'll note that for the vast majority of programmers, it's likely to be frustrating for quite a while.
romwell · 2018-02-23
>"maybe you don't need a c++ like doubly linked list, and here's why" write-up?
Done and done, you're welcome:
http://cglab.ca/~abeinges/blah/too-many-lists/book/
steveklabnik · 2018-01-04
What's easy and hard in Rust isn't the same as what's easy and hard in other languages. As a beginner, don't try to learn Rust by implementing data structures, as you need to know a lot of Rust to do it correctly. Here's an entire book on writing linked lists, for example: http://cglab.ca/~abeinges/blah/too-many-lists/book/
What did you do so far to learn? How do you learn other languages, and what other languages do you know?
blub · 2017-10-03
Take for instance http://cglab.ca/~abeinges/blah/too-many-lists/book/README.html. I could feel the frustration when reading those compiler errors.
I mean it's a list, one of the simplest data structures to implement, I was doing that stuff in high-school.
But it's not just about a particular example, instead I get a general feeling of inaccessibility when reading Rust code. It's not enough to know C or C++, one has to understand the Rust way. This might seem unfair to complain about, but I didn't have any such issues when learning e.g. Swift or Objective-C, to give an example of non-GC languages.
kybernetikos · 2017-09-01
If I can't code some data stuctures in a language I don't feel like I know it, so I would like something like this too.
The closest I found was the 'too many linked lists' book, which I learned a lot from. http://cglab.ca/~abeinges/blah/too-many-lists/book/
chancancode · 2017-08-31
Have you read "Learning Rust With Entirely Too Many Linked Lists"[1]? I think it will be quite helpful for these kind of situations. It walks you through all the possible tools in the language that is available to you, and at the end, if you just want to write it how you would in C, you could always do it "unsafely" with raw pointers (which is no worse than C).
---
[1] http://cglab.ca/~abeinges/blah/too-many-lists/book/
rustacean · 2017-06-19
Thank you. But it seems not finished?
I am trying to implement some basic data structures and algorithms in Rust, but the compiler nearly kills me. Is there any data structure & algorithms implementation tutorials for Rust newbies, like Learning_ Rust_With_Entirely_Too_Many_Linked_Lists[1]?
[1]:http://cglab.ca/~abeinges/blah/too-many-lists/book/README.html
fny · 2017-02-06
See "Learning Rust with Entirely Too Many Linked Lists"
http://cglab.ca/~abeinges/blah/too-many-lists/book/
moosingin3space · 2017-02-06
If you _really_ want to learn how to use Rust to write graph-like data structures, look at this: http://cglab.ca/~abeinges/blah/too-many-lists/book/