Conversation

So I wrote this (pseudocode incoming): fn open_window() -> Future<Window> { let (sender, receiver) = oneshot::channel(); let window = Window::new(); window.on_open(|| { sender.send(window); }); receiver }
2
29
So the oneshot::channel() call creates a future (`receiver`) and a thing I can use to resolve the future with a value (`sender`). So, when the window opens, the future gets resolved with the window handle.
1
20
But the Rust compiler saw this code and was having none of it. Why? The `send` call consumes `sender`, and I'm calling it in a function which can be called multiple times (windows can open and close repeatedly during their lifetimes), so I'm not allowed to consume `sender`.
4
50
And so I had to rewrite my code to make sure I actually only tried to resolve the future the _first_ time the callback function got called, thus ensuring I'm not erroneously trying to resolve a future that's already been resolved.
2
59
This is pretty tame compared to how else Rust is able to verify resource management and concurrency for you, but I figured it was an example so simple it's worth recounting. Because this is new. Your current language can't spot this. No, sit back down, not even Haskell (yet).
7
212
You might be tempted to object, "yeah, but what if I'm sure my window is only going to open once? The type checker is just in my way then." That's like being sure you only need to store the last two digits of the year. Shame on you.
3
199
People keep asking, so here's the fix: let (sender, receiver) = channel(); let sender = Some(sender); ... window.on_open(|| { if let Some(sender) = std::mem::replace(&mut sender, None) { sender.send(window); } }); ...
6
68
Ie. we swap out the value of `sender` in place and leave a null value for the next caller. That way `sender` isn't consumed (just changed, which is OK because we do actually own it) and we can consume the value we took out of it as much as we like.
4
42
the std::mem::replace scares me (being one of those js peeps it just seems so low level). Would this work in this case? if let Some(sender) = sender.take() { ... } Awesome thread!
3
std::mem is a really weird module, an amalgam of totally basic bread-and-butter utility functions that should really be in the prelude, like swap() and replace(), obscure but benign things like align_of(), and eldritch horrors transmute() and uninitialized()
2
15