Shared data across chained futures returned from method (data like self and local vars)?

I am relatively know to Rust and use futures 0.1 (but will upgrade hopefully soon). I have a question regarding the shared use of shared data and references across futures:

There is a method do_sth() that computes a HashMap with the help of two futures, combined with and_then(). The resulting future is returned, resolving eventually in the HashMap. The resulting HashMap is created as local variable and mutated in both futures and both futures call other methods in &self and access other shared local variables in their closures. This however doesn't seem to work the way I expected and the compiler errors with closure may outlive the current function and if I have both futures use move I am not allowed to. Both errors I think I vaguely understand, but I am not sure how to properly fix them. This playgrounds exemplifies my problem(s):

Can this maybe fixed with lifetimes? Any input is appreciated!

Pass down results by value in a tuple.

Nice, thanks a lot! So it seems accessing self is okay as long as it is not mutating? How could I go about this when &self is declared as mut (as in pub fn do_sth(&mut self, ...)), like in this playbook. The compiler raises the error use of moved value: `self` , but I am not quite sure what do about it.

I mean, the exact same trick works?

But you should not in general be using &mut self with concurrent code, it's a recipe for disaster. (And while my workarounds compile, they are emphatically not elegant.)

If you need shared mutability, you either have to use some sort of explicit synchronization (atomics for primitives, mutex/RwLock for anything more complex), or implicit synchronization in the form of queues and message passing.

2 Likes

Thanks, that's great and I should have tried that before. I can definitely see some of the problems that can arise from data races and should be able to avoid them in my particular case. Thanks for your words of warning though.

You kindly answered my initial question already, but if I may, I have yet another follow-up question: If the called methods within the futures borrow self for the struct lifetime 'a, like fn do_sth_else(&'a mut self) requires, the compiler complains about "cannot move out of self because it is borrowed". I tried returning self as well from fn do_sth_else() to follow your examples above, but couldn't get it to work. Am I mistaken that all futures are ultimately run within lifetime 'a? My (clearly wrong) assumption so far was, that the futures then can also access borrowed values one after another.

&'a mut Type<'a> is an anti-pattern. Due to invariance of the type parameter of a mutable reference, this construct requires the referent to be borrowed forever. It's never what you want.

Why did you add the explicit lifetime? It's not needed.

1 Like