Hacker News new | ask | show | jobs
by sakisv 167 days ago
As someone who's only did a couple of small toy-projects in rust I was never annoyed by the borrow checker. I find it nothing but a small mental shift and I kinda like it.

What I _do_ find annoying though and I cannot wrap my head around are lifetimes. Every time I think I understand it, I end up getting it wrong.

2 comments

Lifetimes are the input to the borrow checker, so it doesn't make much sense to say you have never been bothered by the borrow checker but you are bothered by lifetimes.
Due to lifetime elision you can mostly skip lifetimes if you leave a bit of performance on the table.
How does lifetime elision affect performance? I thought the compiler just inferred lifetimes that you would have had to manually annotate. Naively, it seems to me that the performance should be identical.
Strictly speaking, elision just adds lifetimes based on common patterns, so yes, it wouldn't directly affect performance.

I believe your parent is implying that if you skip using a lifetime and do something else instead to make it easier, that may be less performant.

Exactly.

Cloning values, collecting iterators into Vecs and then continue the transformation rather than keeping it lazy all the way through. Skipping structs/enums with references.

I think his point is the lifetime you’d put there is identical to the lifetime that is inferred/elided. So there is literally no difference.
I thought they meant the case where you go "ugh, I don't want to write a lifetime here" and then change your code, because you have to. If you don't have to, then yes, there's literally no difference.
Ah, that's a fair point. In that case then yes, I have been bothered by the borrow checker very much indeed lol.
Somehow at some point lifetimes started clicking for me. I think the key was when I understood that in a function, not everything needs the same lifetime. e.g.

    struct MyRef<'a> { item: &'a i64 }
    struct MyType { items: Vec<i64> }
    impl MyType {
        fn get_some_ref(&self, key: &usize) -> MyRef<'a> {
            MyRef { item: &self.items[key] }
        }
    }
the function this way is incorrect. When I was a beginner, I would have thought that every & in the signature needed a lifetime. In a slightly complicated code, the borrow checker then demanded lifetimes everywhere, they'd infect everything, but the code would still never compile.

Then I understood that not everything needs to be tied to the same lifetime. In this example, MyRef should be tied to the MyStruct, but not to the `key`:

        fn get_some_ref<'a>(&'a self, key: &usize) -> MyRef<'a>