And the complaint is that Rust semantics makes this hard. Well yes, Rust makes it uncomfortable to shoot your own foot, that’s kind of the point.
And the complaint is that Rust semantics makes this hard. Well yes, Rust makes it uncomfortable to shoot your own foot, that’s kind of the point.
I think you are misunderstanding the author's point. I think that they'd probably agree that the (lack of) ergonomics of closures are a necessary result of the safeguards that Rust provides.
They point is more that, given that closures have somewhat frustrating ergonomics, it was probably a bad choice to base Rust's primary concurrency system on closures.
Disclaimer: this is not my opinion, just paraphrasing what I believe the author's point is. I found the post a bit strange, it seems to end rather abruptly. It doesn't seem to address the main question it seems to raise: what does this mean for async Rust and why is this bad?
Rust still doesn't support use-after-free, so you can't reference a temporary object and use it in another thread that will outlive it :)
In TFA the second do_work_and_then() example doesn't compile, because it has a UAF vulnerability that borrow checker has detected and prevented.
https://doc.rust-lang.org/std/mem/index.html
Genuine question, I don't mess around with memory typically.
You can use an `unsafe {}` block to call literally libc::free(), or dereference a random raw C pointer, or do something else crashy. However, when talking about Rust's safety rules it's usually assumed we're not talking about code bypassing these rules on purpose.
my_fn(|| {
db.store(42);
});
db.drop();
(Assuming you can just drop the database object, the semantics don’t really matter but the idea is the same.) The OP wants an easy way to do this but this is just not an easy thing to do. How can the closure guarantee that the database object will exist if my_fn decides to sleep for a couple seconds? Most languages do not have this problem because either: they use a garbage collector (Java and it’s cousins, Python, Go) or they are not safe (C, C++). Rust is in a particularly difficult (and ambitious and exciting!) intersection where this problem is tricky.The `&mut Database` sort of implies that the Database handle doesn't do its own locking or other needed state tracking - it just relies on the exclusivity of `&mut` in Rust to be sure that nobody else is modifying the database handle at the same time.
If the API used `&Database`, then it would have to be more flexible for simultaneous use of the handle. And then the closure would be (a bit) easier to call too, because it's not tracking that exclusive reference.
If the API used a reference counted `Database` handle, then it would release even more restrictions of lifetime management, etc. You can implement all of these in Rust.
In other languages, you usually end up with alternative two or three.
If you try to simultaneously take alternative 1 and use it in a way that's not supported, that would be shooting yourself in the foot. Except Rust says compile error instead.
The closure can write to database, and after the call, there’s no way to know if it has already written, or even if it’s writing to it right now.
That would be a Mutex<>, the author mentions it in the comments. This would solve the “writing at the same time issue”, but not the lifetimes, so you’d need another change.
Instead of trying the mess of implementing special closures, you could just make your db static.