Reading List
The most recent articles from a list of feeds I subscribe to.
A couple of Rust error messages
Hello!
I’ve been doing Advent of Code in Rust for the past couple of days, because I’ve never really gotten comfortable with the language and I thought doing some Advent of Code problems might help.
My solutions aren’t anything special, but because I’m trying to learn, I’ve been trying to take a slightly more rigorous approach than usual to compiler errors. Instead of just fixing the error and moving on, I’m trying to make sure that I actually understand what the error message means and what it’s telling me about how the language works.
My steps to do that are:
- fix the bug
- make a tiny standalone program reproducing the same compiler error
- think about it and try to explain it to myself to make sure I actually understand why that error happened
- ask for help if I still don’t understand
So here are a couple of compiler errors and my explanations to myself of why the error is happening.
Both of them are pretty basic Rust errors, but I had fun thinking about them today. I wrote this for an imagined audience of “people who know some Rust basics but are still pretty bad at Rust”, if there are any of you out there.
error 1: a borrowing error
Here’s some code (rust playground link):
fn inputs() -> Vec<(i32, i32)> {
return vec![(0, 0)];
}
fn main() {
let scores = inputs().iter().map(|(a, b)| {
a + b
});
println!("{}", scores.sum::<i32>());
}
And here’s the compiler error:
5 | let scores = inputs().iter().map(|(a, b)| {
| ^^^^^^^^ creates a temporary which is freed while still in use
6 | a + b
7 | });
| - temporary value is freed at the end of this statement
8 | println!("{}", scores.sum::<i32>());
| ------ borrow later used here
help: consider using a `let` binding to create a longer lived value
|
5 ~ let binding = inputs();
6 ~ let scores = binding.iter().map(|(a, b)| {
|
For more information about this error, try `rustc --explain E0716`.
This is a pretty basic Rust error message about borrowing, but I’ve forgotten everything about Rust so I didn’t understand it.
There are 2 things I didn’t know / wasn’t thinking about here:
thing 1: Variables are semantically meaningful in Rust.
What I mean by that is that this code:
let scores = inputs().iter().map(|(a, b)| { ... };
does not do the same thing as if we factor out inputs() into a variable, in this code:
let input = inputs();
let scores = input.iter().map(|(a, b)| { ... };
If some memory is allocated and it isn’t in its own variable, then it’s freed
at the end of the expression (though there are some exceptions to this
apparently, see rustc --explain E0716 for more). But it does have its own
variable, then it’s kept around until the end of the block.
In the error message the Rust compiler actually suggests an explanation to read
(rustc --explain E0716), which explains all of this and more. I didn’t notice
it right away, but once I read it (and Googled a little), it really helped me.
thing 2:. Computations with iter() don’t happen right away.
This is something that I theoretically knew, but wasn’t thinking about how it might relate to compiler errors.
When I call .map(...), that doesn’t actually do the map right away – it
just sets up an iterator that can do actual calculation later, when we call
.sum().
This means that I need to keep around the memory from inputs(), because none
of the calculation has even happened yet!
error 2: summing an Iterator<()>
Here’s some code (rust playground link) (This isn’t the actual code I was debugging, but it’s the fastest way to demonstrate the error message)
fn main() {
vec![(), ()].iter().sum::<i32>();
}
This has a pretty obvious bug: You can’t sum a bunch of () (the empty type)
and get an i32 as a result. Here’s the compiler error, though:
2 | vec![(), ()].iter().sum::<i32>();
| ^^^^^^^^^^^^^^^^^^^ --- required by a bound introduced by this call
| |
| the trait `Sum<&()>` is not implemented for `i32`
This was very confusing to me – I’d expect to see an error saying something
like Sum is not implemented for Iterator<()>. But instead it says that Sum is
not implemented for i32. But I’m not trying to sum i32s! What’s going on?
What’s actually going on here is (thanks to some lovely people who helped me out!):
i32has a static method calledsum(iter: Iterator<i32>), that comes from theSumtrait. (defined here for integers)Iteratorhas asum()method that calls this static method oni32(defined here)- when I run
my_iter.sum(), it tries to calli32::sum(my_iter) - But
i32::sumisn’t defined forIterator<&()>! - The type parameter in
Sum(eg)Sum<&()>refers to the type of the iterator that’s being passed toi32::sum() - as a result, we get the error message
the trait Sum<&()> is not implemented for i32
I might not have gotten all the types/terms exactly right here, but I think that’s the gist of it.
This was a good reminder that sometimes methods (like sum() on Iterator are
defined in slightly indirect/counterintuitive ways and that you have to hunt
down the details of how it’s implemented to understand the compiler errors.
(my actual bug here was actually that I’d accidentally added an extra ; in my
code, which meant that I accidentally created an Iterator<()> instead of an
Iterator<i32>, and the confusing error message made it harder to figure out that
out)
Rust error messages are cool
I found these error messages pretty helpful, I especially really appreciated the --explain output on the borrowing error.
The cheese grater that saved Christmas
Opening Node developer tools just got easier
New to Mastodon? These 10 minutes are very important
I've been on the fediverse/Mastodon since 2019 and have made some amazing friends.
At the moment, I run SmallCamp, and help moderate Fosstodon along with a fantastic team and over 250 300 350 600 800 950 patrons.
Part 1: looking like an actual person.
- Please fill out your bio and make an #introduction post with that hashtag, yes. Look at what other people are posting about to get an idea.
- Put up a nice avatar that you like (whether of yourself or your hobbies).
People are much more welcoming when they can see who you are.
Trust me — these two things really help when people have locked their profiles and you're trying to add them.
With these two steps, we are trying to tackle the problem of: "Yes, you know you're a safe person, but how do I know that?"
People have no qualms about hitting reject… none of them are chasing a high follower count.
So, anyway, once these two steps help you follow more people, your timeline looks more lively. And you want to stay. And you follow more people. And it's a cycle, see? 🙂
Remind yourself that people on the fediverse/Mastodon have been cultivating a safe space for themselves for months (and for most of us, it is more likely to be years).
Anytime a lot of people join at once and in a short amount of time, like right now, their guard tends to be more up than usual.
The culture on the fediverse is a bit different. And remember, any new social network is always hard at first. It gets better.
Part 2: make a few posts.
Keep posting about your day and thoughts like it's 2007 and Twitter hasn't yet taken off. Just vibe. We're all here to chill. Mostly.
Find your community, not an audience.
Post about what you had for lunch.
Send a photo out into the internet — as long as it's safe for you to do so — about the beach you're sipping beer at.
Introduce your dog with a selfie or a regular photo.
Psst! Monetisation… that kind of stuff doesn't work very well here. We're not Twitter v2.0. We're just trying to bring the good old, open, social web back.
Part 3: learn the culture.
It's like Twitter, but it's not Twitter.
You'll notice a few things that we care about:
- Adding a "content warning" to your posts. This is especially true for politics, or any kind of content that might trigger someone. Remember safe space? Yup.
- Writing alt text for images… we're big on this. A lot of disabled people use Mastodon regularly, and in any case, it helps everyone. I know I've used alt text before to make sense of some images sometimes.
You're ready. Go have fun? Say hi.
I encourage you to get in touch over email by using the following convenience link for any discussion: comment via email.