# FUTURES CONCURRENCY III Reading notes
###### tags: `reading-club`
https://blog.yoshuawuyts.com/futures-concurrency-3/
Leave notes below
---
## (eholk) Are there ever cases where we want to blend the different concurrency modes?
In other words, are we sure we don't need/want the extra flexibility afforded by `select!`?
Niko's blog post:
https://smallcultfollowing.com/babysteps/blog/2022/06/13/async-cancellation-a-case-study-of-pub-sub-in-mini-redis/#enter-select-our-dark-knight
```rust
select! {
// accessess subscribers
f = subscribers.next() => {
}
// accesses input
m = input.next() => {
match m {
AddSubscriber => {
// ok because we dropped
// subscribers.next() before
// entering the body
subscribers.push(...);
}
}
}
}
scope(|s| {
s.spawn(async move {
// subscribers: tokio::StreamMap
while let Some(s) = subscribers.next().await {
}
});
s.spawn(async move {
for i in inputs {
subscribers.push(..);
}
});
})
```
nikomatsakis: what I want is something like a "token" where you both get an `&mut` but you share a single token that lets you do it. (language feature). You can't actually do this with locks unless the lock gets released on the await
[Deferred borrows](https://web.archive.org/web/20220713182926/https://cfallin.org/pubs/ecoop2020_defborrow.pdf) - ([eholk's review](https://blog.theincredibleholk.org/blog/2022/07/29/safe-flexible-aliasing-with-deferred-borrows/))
tmandry: Is this the right shape for the code we want to support?
nikomatsakis: You could use actors. This shape seems useful, but not sure.
"Anyone who uses an async lock probably should've used an actor instead" - because this pattern doesn't work well.
nikomatsakis: These tasks are conceptually related and happen to share state. Using actors would be to organize your code around the data.
Rust has strong support for spatial separation (different data) but relatively weak for temporal data (same data, different times).
tmandry: this is a pretty common rust thing, right? to organize around data?
nikomatsakis: yes. it is, and I do think that's part of what makes Rust reliable.
nikomatsakis: why does Rayon work? I guess because you just can't do this sort of thing, and because when you have locks you have the ability to release the lock when waiting.
I would like it if when you "open" these `&mut`...
eholk: merge merge types, select does a better job interleaving streams of different types, but you can do it with an enum.
```rust
fn foo() -> impl Debug {
if {
return Either::Left(22);
} else {
return Either::Right("22");
}
}
```
tmandry: anonymous enums could help
nikomatsakis: the problem I see is that anonymous enums, you have to match on what comes out? I guess if all the inputs are different types. the other thing i've thought about is some API that lets you build up the stream + the code to handle the stream (a closure), but
nikomatsakis: ...or...maybe anonymous do work, if the match is that each arm has to have a distinct type.
```rust
let stream: impl AsyncIterator<Item = u32> = ...;
let stream1: impl AsyncIterator<Item = f32> = ...;
let stream2: impl AsyncIterator<Item = u32> = ...;
merge!(stream, stream1, stream2).foreach /* (u32|f32) */ match {
x: u32 => {
}
x: f32 => {
}
}
struct MergedStream<sink type T> {
}
```
[Matching with closures in C++](https://cs.android.com/android/platform/superproject/+/master:art/runtime/base/message_queue.h;l=79;drc=051390df944725ced8942cbbb286d00518bf5718)