---
# System prepended metadata

title: 'Deep dive: IntoFuture autoderef + #42940'
tags: [deep-dive]

---

---
title: wg-async meeting 2023-08-17
tags: deep-dive, wg-async, minutes
date: 2023-08-17
url: https://hackmd.io/G6ULofyXSIS4CK9u-jwYRg
---

# Agenda

* Initial issue: https://github.com/rust-lang/rust/issues/111546
* Autoderef PR https://github.com/rust-lang/rust/pull/111773
* [Analysis of Rust issue #42940](/83sY9XQjSiK79QdnqK0F3Q)

# Attendance

Present: tmandry, TC, yosh, eholk, vincenzo

# Autoderef on `.await` PR

TC: We discussed this in the meeting on Monday.  There seem to be tradeoffs here.  At a minimum, it probably needs a crater run.

vincenzo: Looks like that the reason is that we could simplify the API:

from:

```rust!
assert_eq!(shared.as_ref().await.id, 4);
```

to:

```rust!
assert_eq!(shared.await.id, 4);
```

Sure why not? I am not able to see what is the impact of possible api that relay on `as_ref()`?

## Compatibility

tmandry: Can this break existing code? Is this a change we need to consider over an edition?

vincenzo: We should be careful about this, but if it's compatible we should do it.

## Do we feel this just because syntax

tmandry: There's an argument from consistency with method dispatch.

TC: I wonder if we would feel the same way if we had gone with prefix `await` or postfix space syntax.

yosh: I think we would.  Striving for async Rust to be like sync Rust, it could make sense.

## "just add a `.await`"

yosh: https://github.com/rust-lang/rust/issues/111546#issuecomment-1557577198

```rust
// sync
fn johns_id() -> Option<u32> {
    USER_IDS.get("John Doe").copied()
}

// async, current
fn johns_id_no_autoref() -> Option<u32> {
    USER_IDS.force().await.get("John Doe").copied()
}

// async, proposed
fn johns_id_with_autoref() -> Option<u32> {
    USER_IDS.await.get("John Doe").copied()
}
```

## Implicit async iterators

Autoref on await would let us do:

```rust 
let mut iterator = AsyncCountingIterator::new();

let first = iterator.await;
let second = iterator.await;
```

instead of 

```rust 
let mut iterator = AsyncCountingIterator::new();

let first = iterator.next().await;
let second = iterator.next().await;
```

## IntoIterator?

tmandry: The other consistency angle I'm thinking of is `into_iterator`.  Do we do it there?

```rust
let foo = vec![];
// Calls <Vec<()> as IntoIterator>::into_iter():
for x in foo {}
// Calls <&Vec<()> as IntoIterator>::into_iter():
for x in &foo {}
```

TC: To summarize, when the language uses `into_iter`, as in `for x in y` syntax, it doesn't do `autoderef`.  Since `Iterator` and `for` is a similar effect to `Future` and `await`, this is a strong analogy.

tmandry: Agree with that summary.

The original example in the issue was:

```rust
use core::future::IntoFuture;
use futures::future::{ready, Ready};
struct Foo;

impl IntoFuture for &Foo {
    type Output = u32;
    type IntoFuture = Ready<u32>;

    fn into_future(self) -> Self::IntoFuture {
        ready(2)
    }
}

#[tokio::main]
async fn main() {
    assert_eq!(Foo.await, 2);
}
```

```rust
(&USER_IDS).await
```

tmandry: People on the lang team have in the past "threatened" to add `.ref` to make that nicer.

yosh: A different way to reason about it could be we should tweak how `into_iterator` works. (Not actually proposing we should though, but it's an option.)

tmandry: It does make me think here, "why couldn't the user just do an `impl IntoFuture` for Foo"?

yosh: [That seems to work?]( https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f4a947542b4c01973d7a37df960eef27) 

eholk: that consumes the `Foo` though. In the example on the issue the thing being awaited is a static so we don't want to (can't?) consume it.

tmandry: Because of postfix `.await`, it's more of a pain to explicitly take a reference. Some lang team members have talked about `.ref` or similar. But we should maybe put more weight on the method dispatch analogy based on this.

TC: What would be the tradeoffs of doing autoderef on `for` loops?

tmandry: It would be confusing.

eholk: With `for` loops there's a convenient place to put the ampersand.

TC: It seems maybe unprincipled to make a decision based only on the syntax that we chose for await rather than its semantic similar to other things in the language.

TC: Do any of the downsides that tmandry mentioned about `for` apply to `.await`?

yosh: Are there any general statements we can make about postfix syntax?

TC: E.g., what if we had postfix `.for(..) { .. }`?  How would we feel about that and about the tradeoffs that tmandry raised there?

tmandry: It does feel fine to lean on the syntax for deciding how to look at this.

eholk: `.await` feels like a method call.  It's not, but it feels that way. 

TC: Interesting aside, during the discussions about choosing the `await` syntax, the fact that postfix dot looked like a field access or method call was one of the downsides people noted.

tmandry: It seems like we need to do a crater run.  It's definitely doing to need an FCP from the lang team.

TC: Do we think that t-types will have a feeling on this?

tmandry: Yes, that's a good point, we should collect feedback there.  It's be a good stance to say that we want this but that we're cautious about problems.

TC: +1

yosh: Thinking about what you said, TC, about it not being principled.... I do think we want principled designs.  If we decide that `.await` should do deref, then we should decide that all postfix syntax should probably do that.  We should take that into account.  That's definite 100% RFC material and lives on the lang team.

TC: +1

tmandry: +1, there should be some principle.

eholk, vincenzo: +1

TC: Postfix `match` syntax... we couldn't do autoderef for that, that would be weird.

tmandry: Right.

yosh: Is the binding mode thing on `match` related to autoderef?

TC: Not really, it follows a different set of rules.

eholk: Are these under discussion on the language side?

tmandry: We have discussed postfix `match`.

yosh: I know of two examples where postfix `match` is being considered.  Here are two examples:
```rust
// for-loops
for match in my_iter {
    x => {}
    y => {}
}

// try statements
try { .. } match { .. }
```

tmandry: That's different than what I think of with respect to postfix `match`.  I think of `.match { .. }`.

## Short reprise of `Future::map`

tmandry: We don't really have time to dive into the second issue.

TC: Maybe we could discuss the items from last week for the people who weren't here.

TC: Here's that meeting: https://hackmd.io/LfWcsTSYTPK5TuORJ4l22g

(Discussion about `Future::map`.)

TC: I did have a thought about this after the meeting last week...

TC: Maybe we should just add this method to a separate trait (that could later be implemented by other things like `Option`).  So rather than:

```rust
pub trait Future {
    fn map<U, F>(self, f: F) -> Map<Self, F>
    where
        F: FnOnce(Self::Output) -> U;
}
```

We would add:

```rust
trait MapOnce<T> {
  type Wrapped<U>;
  fn map<U, F>(self, f: F) -> Self::Wrapped<U>
  where
    F: FnOnce(T) -> U;
}
```

And we would add an appropriate blanket impl.

(Some discussion followed.)

(The meeting ended here.)
