Me: I just wrote some multi-threaded code.
Rust: Sounds exciting!
Me: Nothing wild. Just a little bit of spawning and joining.
Rust: Great, let me see.
Me: Here we go.
Rust: Oliver, what the hell do you think you are doing?
Me: Uhm, what? Why?
Rust: See, this object here does not live long enough. It lives until here, but you are using it here.
Me: Hm, if it lives up to here, looks to me like that should be long enough?
Rust: No, because you are using it on a different thread.
Me: Oh. I see. I know, I'll just slap some lifetime annotations on it. Hm, what should it be? Like this? No, that's redundant. Does it need to be static? No, it can't be static. Maybe ...
Rust: Sorry, Oliver, I think I did not make myself sufficiently clear. Lifetime annotations won't help here.
Me: Really? Why? Then, what else?
Rust: You are trying to use an object owned by one thread on another thread. I'm sorry, Oliver, I'm afraid I can't do that.
Me: What's the problem?
Rust: What if the owning thread dies before you are trying to use the object? That would pull out the rug under you. Elementary, my dear Oliver, elementary.
Me. Oh, I see. I need to move the object to the other thread.
Rust: To move to another thread, the object needs to be sendable.
Me: How do I make an object sendable?
Rust: Most objects are already sendable.
Me: Then, what's the problem?
Rust: You need to enforce it.
Me: How do I enforce an object to be sendable? Do I need to implement some trait?
Rust: No need to implement anything. I can check for you whether an object is sendable.
Me: Then, please do so?
Rust: You're using generics, so you need to declare that you are using a sendable object.
Me: Oh, ok.
Rust: Consistently, please.
Rust: I see you are using a simple reference counter to share data between objects. But a simple reference counter is not sendable.
Me: Ok, I'm going to use an atomic reference counter.
Rust: That's the spirit, son.
Me: That was so much simpler in Scala.
Rust: Sure, if you are fine with the massive overhead. Long runtimes, big cloud bills.
Me: But it was simpler.
Rust: Yeah, like when you invested tons of time with Akka Streams to make a multi-threaded app that turned out in the end to be effectively single-threaded.
Me: Yeah, that sucked. They said Akka was reactive.
Rust: You gotta hand it to them: it did react eventually.
Me: Yeah, after three days.
Rust: They said it was reactive, not fast.
Me: Ugh, forget about Akka. In Scala, I could just use Futures.
Rust: You know well that a Future is not guaranteed to complete within any given time, even if the inner code has already finished ages ago. Remember that weird server timeout bug that took you days just to diagnose?
Me: Well, it depends on the thread pool.
Rust: You have no idea what are all the things it depends on.
Me: There should be a simpler way.
Rust: There is. Just do it properly.
Me: And what is the problem now?
Rust: You can't move your object and try to keep it, too.
Me: Ok, I suppose I can clone it?
Rust: Then implement a clone method.
Me: Why am I getting a stack overflow?
Rust: It is never a good idea for a clone method to call itself.
Me: I just wanted to simplify the trivial cases.
Rust: It is still not a good idea for a clone method to call itself.
Me: I can't believe I have gotten myself into this.
[later, after much mocha and Metallica]
Me: Ok, here's yet another attempt. I wonder what you're going to tell me is wrong this time.
Rust: That would work.
Me: Really? It's working? Seriously?
Rust: Yep. Let me build it for you.
Me: You mean, it's totally thread safe? Really?
Rust: Absolutely! Guaranteed!
Me: Wow! I can't believe it! This is so awesome! Thank you! I love you!
Rust: You're welcome!