# Async fundamentals ere long ago (2021)
## 2021-12-20
### Problem with `with` clauses
```rust
fn deserialize_and_print_later(
deserializer: &mut Deserializer,
bytes: &[u8],
)
where in('static) T: Deserialize + Debug
{
thread::spawn(|| {
thread::sleep(1);
let object = T::deserialize(deserializer)?;
println!("{:?}", object);
});
}
```
Not good enough.
```rust
trait ContextFree: Sealed {}
// This is stronger than we need, but works in
// all cases.
fn deserialize_and_print_later(
deserializer: &mut Deserializer,
bytes: &[u8],
)
where with(ContextFree) T: Deserialize + Debug
{ ... }
```
```rust
// This is exactly what we need.
fn deserialize_and_print_later(
deserializer: &mut Deserializer,
bytes: &[u8],
)
where with(Send + 'static) T: Deserialize + Debug
{ ... }
```
```rust
dyn Debug
// desugars to
dyn with(ContextFree) Debug + 'static
// or you could write..
dyn with(Bound) Debug + '_
```
```rust
where
T: with(Send) AsyncTrait<async_fn: Send> + Send
```
`* Send`?
set interpretation
* `with(cap1, cap2)` vs `with(cap1) with(cap2)`
* `with(Bound)` means "all capabilities meet `Bound`"
* default for an impl is empty set
* `with(_: Send)`
* `with(Send)`
* `with(cap1: Type)` or `with(cap1: impl Trait)`
:alternative-universe.gif:
* What if we ONLY HAD `Send * Bar` and no `+`...
* then you could do
* `where T: Send * Debug` // in either order
* `where T: Send, T: Debug` // distinct thing
* Meaning:
* `T: Foo * Send` means "all RPITIT in Foo are Send"
Some form of opt-in for non-RPITIT?
```rust
trait Foo {
// too strong! This makes `Foo * Send` != `Send`
type Bar: if (Self: Send) Send
}
trait Foo {
// not this, but like this, to mean that `T: Foo + Baz` where `Baz` is an auto trait
// means `T: Foo<Bar: Baz> + Baz
#[selfish]
type Bar;
}
```
## 2021-12-16
### year end blog post
```rust
async fn main() {
for await b in bottles() {
send_request(b).await;
}
}
async fn* bottles() yields String {
for i in (0 .. 99).rev() {
yield format!("{i} crabcakes on the wall");
}
}
```
What are the pieces we need to make this beautiful code work
* Async fundamentals
* Async functions
* Portability
* async fn main
* tcp stream or something
* Generator working group
* Async iterator trait
* Generator syntax
* Await patterns
* Polish / tooling
* Beautiful diagram
* draw.io!!!!
#### where we were
```rust
#[tokio::main]
async fn main() {
for await b in bottles() {
send_request(b).await;
}
}
impl Stream for BottlesStream {
fn foo(self: Pin<&mut Self>) {
/* OMG I AM DEAD */
}
}
```
```rust
Pattern = ...
| await Pattern
| ? Pattern
for await? x in fallible_io_thing() {
}
for? entry in dir.entry() {
/* instead of let entry = entry? */
}
let await x = y; // equivalent to y.await;
let (await x, y) = foo(); // returns (impl Future, usize)
match foo() {
(await x, y)
}
match foo() {
Some(await x)
None
}
match foo() {
Some(await x) if something
}
```
```rust
for x.await? in y {
}
```
### tale of two dyns
#### goals
* supporting `async fn` calls;
* `impl Trait` in argument and return position, so long as `Trait` is dyn safe;
* supporting "by value" `self` methods;
* supporting cloning of trait objects[^caveat];
* supporting trait objects that are "partially dyn safe".
(what other things do we want for dyn that we are not trying to get now)
#### use cases
* embedded 1
* library uses async fn in a trait and dyn trait
* embedded user of library is able to invoke it without calling box to box futures
* by e.g. inlining OR the enum solution?
* tight loop with reuse
* reuse: invoke `foo.bar()` a lot for the same foo
* something something uses `&mut` and avoids alloc
* regular code
* uses box, it's easy, it can clone things
* async drop
* I drop something
* embedded async drop
* also in
* tight loop up to N bytes
* can handle this by making your own trait and doing the erased serde
* question mark:
* measure the size of futures?
#### "standard vtable format"
* `dyn Trait` it has a vtable that includes
* all the regular fns like today
* for these cases...
* argument position...
* what we need
* define how the caller will "package up" the argument in the way the vtable expects
* how the vtable will "unpackage it" for the underlying fn
* cases
* Impl trait in argument position
* vtable expects a dynx
* dynx where the pointer type is
* &
* &mut
* or Box
* depending on our analysis of the trait
* By value self in argument position
* vtable takes a `*mut T`, effectively `&move`
* iow, callee owns the `T` but not the memory the `T` resides in
* vtable shim does `let x = *x` and then calls underlying fn with `x`
* perhaps some more efficient version
* return position...
* what we need
* define how the callee will "package up" the argument in the way the vtable expects
* how will the caller "unpackage it"
* By value self in return position
* vtable: always takes an out pointer
* compiles `*outptr = underlying_fn()`
* no normal caller :)
* because `foo()` fails to type check if return type is `?Sized`
* but there is an intrinsic that we add
* `std::ptr::write` basically
* takes a `F: FnOnce() -> T` and a `*mut T` (or whatever) and calls the function, writing its result into the raw pointer
* now we can write `Box<T: Clone>` impl to use this intrinsic
* Eh! Problem `trait Clone: Sized` means we can't have `dyn Clone: Clone`, wtf do we do
* Impl trait in return position
* vtable returns a dynx
* callee can use box
* for the case of "inline wrappers" etc
* we could customize the mapping
* for each of the above:
#### Impl trait in arg
```rust
fn foo(x: impl Len) {
fn helper(x: &dyn Len) {
...
}
helper(&x)
}
```
you wrote
```rust
#[dynify]
fn foo(x: impl Len) {
...
}
```
```rust
fn foo(x: impl Len) {
fn bar(x: dynx<'_> Len) {
...
}
bar(dynx!(x))
}
```
```rust
fn foo(x: impl Len) {
foo::monomorphized(&x as &dyn Len)
}
impl fn#foo {
fn monomorphized(x: impl Len) {
}
#[inline(always)]
fn inline(x: impl Len) { .. }
}
foo(...);
foo::monomorphized(...);
```
```rust
#[salsa::jar]
struct Jar(
foo,
bar,
);
#[salsa::memoized]
fn foo(x: impl Len) {
foo::monomorphized(&x as &dyn Len)
}
#[salsa::memoized]
fn bar(x: impl Len) {
foo::monomorphized(&x as &dyn Len)
}
impl fn#foo {
fn monomorphized(x: impl Len) {
}
#[inline(always)]
fn inline(x: impl Len) { .. }
}
#### but
```rust
fn foo(x: impl AsyncIterator<next: Send> + Send)
// if it would be next::Output
fn foo(x: impl AsyncIterator<next(): Send> + Send)
fn foo(x: impl AsyncIterator<next(T1, T2): Send> + Send)
```
```rust
fn foo(x: Box<dyn AsyncIterator<next: Send> + Send>)
```
## 2021-12-13
### RPITIT
#### Bounding function types: What about `const` bounds?
```rust
trait Foo {
fn foo(&self);
}
fn foo<T>(x: T)
where
T: Foo,
const T::foo,
T::foo: const,
{}
```
things to think about
- in favor of the associated type being return
- but what doesn't work
- can't impl traits or add assoc types for fn types
- can't do const as a trait as above (Seems nice)
- if you have `-> Vec<impl Trait>` or `-> (impl Trait, impl Trait)` , feels weird
- whereas `::Output` is very clear about what it is
### dyn
Parts of the plan, in rough order (can stop at any point)
* Allow `&dyn Len: Len` and so on (see below)
* ABI hackery to make by value self work:
* `-> Self` via out pointer
* Allow `self` via "in pointer" and some stuff
* `impl Trait` in argument and return position: subject to **vtable strategy** (can be "always `dynX`") and **caller strategy**
* caller strategy could be something like `dynX<Box>`
* TODO: outline ways we could do this now, maybe with newtypes
* Allow strategies to choose arbitrary pointer types by abstracting with `dynX`
* Allow "slicing" traits with `dynX &Trait`
* Make `dynX` the newer, easier `dyn`
#### `&dyn Len: Len`
We can get pretty far with these, I think
(may require opt-in)
```rust
trait Len {
fn len(&self) -> usize;
}
// Generated
impl<P, T> Len for P
where
P: Deref<Target = T>,
T: Len + ?Sized,
{
fn len(&self) -> usize {
Deref::deref(self).len()
}
}
```
[playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=aa35f5729c35cd68dd81fe4be83e9276)
```rust
trait Iterator {
type Item;
fn next(&mut self) -> Option<Item>;
}
// Generated
impl<P, T> Iterator for P
where
P: DerefMut<Target = T>,
T: Iterator + ?Sized,
{
fn len(&mut self) -> Option<Item> {
T::next(&mut *self)
}
```
#### `DerefOwn`
* Allows moving out of a smart pointer
* Including partial moves
* But requires more steps than Deref/DerefMut
```rust
trait DerefOwn: DerefMut {
// This type manages the allocation, but does not
// own the contents after a deref_own.
type Residual;
// Safety: The returned residual must outlive
// the returned OwnedRef.
// This will be enforced by the compiler.
unsafe fn deref_own(self) -> (Self::Residual, OwnedRef<'static, Self::Target>);
fn into_inner(self) -> Self::Target where Self: Sized, Self::Target: Sized {
let x = self;
deref_own!(x);
x.into_inner()
}
}
```
[playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=376974034ee30ed479b5e2315942b1ad)
## 2021-12-09
* RPITIT implementation
* `'static` hack for lifetimes inherited from parent
* We need to move these desugarings to something you would actually write
* In particular, I'm concerned about `where T: Foo<'a>` when `'a` does not appear in the bounds -- when we use `'static`, that becomes `T: Foo<'static>'`, but that is not true
* Desugared type alias has a conceptually different set of generics from the function; we should just copy them
### New RFC
* You can write `fn foo() -> impl Trait` in traits and in impls
* it desugars to
* `type foo<...>: Trait` in a trait
* `type foo<...> = impl Trait` in an impl
* You can write `fn foo() -> type` in an impl
* but do you have to write `type foo = type` too?
* if defined using impl trait in the trait, add it?
* what happens if you put `type foo = impl Trait` and `fn foo() -> type`?
* impl has to match signature from *outside* the defining scope
* how many lifetime parameters does the associated type get?
* specifically for async fn, change the desugaring to add an extra fn parameter `'x` which is
* introduce shorthand for `T::foo` where `foo` is a GAT
* expands to `for<'a> T::foo<'a>`
```rust
trait Foo {
fn foo(&self) -> impl Debug;
}
// Error: signature of `foo` is -> impl Debug not -> ()
impl Foo for () {
type foo = impl Debug;
fn foo(&self) -> () {
()
}
}
// Error: two definitions of `foo`
impl Foo for () {
type foo = ();
fn foo(&self) -> impl Debug{
()
}
}
// OK: Not refined
impl Foo for () {
fn foo(&self) -> impl Debug{
()
}
}
// OK: Refines to `()`
impl Foo for () {
type foo = ();
fn foo(&self) -> () {
()
}
}
// OK: Refines to `()`
impl Foo for () {
type foo = ();
fn foo(&self) -> Self::foo {
()
}
}
fn bar() {
let x: <() as Foo>::foo = ...;
// ^^^^^^^^^^^^^^^^
let x: _ = <() as Foo>::foo();
// ^ ??
}
```
```rust
trait Foo {
type bar<'x>;
fn bar<'a, 'b, 'c>(x: &'a u32, y: &'b u32) -> Self::bar<'c>
where 'a: 'c, 'b: 'c;
}
impl Foo for () {
type bar<'x>
fn bar<'a, 'b, 'c>(...) -> Self::bar<'c>
where 'a: 'c, 'b: 'c
// ^^^^^^^^^^^^^^ early bound (b/c 'c appears in where clauses)
{}
}
```
```rust
fn foo<T: Foo>() where <T as Foo>::bar: Send {}
```
### Dyn
* [dyn trait design outline](https://hackmd.io/ZgcyvcklRba50m53pg3wkA)
* supporting clone for `Box<dyn Clone>`
* extend `Clone` with an unsafe method
* `unsafe fn clone_to_raw(&self, *mut ())`
* extend `impl<T: Clone> Clone for Box<T>` to be
* `impl<T: Clone + ?Sized> Clone for Box<T>`
* you call `clone_to_raw`
* another way to think about this
* in the vtable for a `-> Self` fn, we put a fn that expects a `*mut Self` and "does the right thing"
* need some intrinsic to call it
* Rc's copy-on-write methods e.g. `Rc::make_mut`
* could make that work for `T: ?Sized`
```rust
struct DynX<trait B> {
x: *mut dyn B
}
```
* if you want to support `-> impl Trait` with dynamic dispatch
* you want to return a `DynX<Trait>`
* in other words:
* "some pointer to something that implements Trait"
* "and has a vtable slot for how to drop that pointer"
* vtable interface:
* in procedural macro, there wasn't one vtable interface
* it was defined by this erased trait that carried the methods we wanted
### The dyner design
Introduce a `DynX<Trait>` type into the standard library:
* by some magic it holds a `*mut Trait` and knows how to drop itself
The vtable for an impl of a trait:
* If method has `-> impl Trait`, vtable expects to return a `DynX<Trait>`
* each impl will require some "glue" to take the actual return value and make it a `DynX<Trait>`
* for example, if it returns some future type `F`
* that may need to be `Box::pin`'d to get a pointer `Pin<Box<F>>`
* and then we attach the vtable to get a `DynX<Future>`
* at the point where we generate the vtable for a given type:
* there is a point in compilation where we are coercing from a known type to a dyn type
* and that is where we do whatever adaptation we have to do
* how do we determine that adaptation?
* for now just assume there is an oracle
* `Oracle(Trait) = adaptation`
* somehow can be overriden on a per-impl basis
* some fixed set of strategies you can pick from
* If method has a `impl Trait` argument, table expects a `DynX<Trait>` as well
* as above, there is some glue, but this glue has to be the same for all instances of the trait
* has to be customized per trait or perhaps some "wrapper" type
* we could probably do some kind of `&move` thing
* so long as trait doesn't have a `'static` bound
* If method returns `-> Self`, we .. do something like we descirbed earlier so that you can invoke this with a custom return pointer
* the vtable has a method takes an explicit `*mut Self`
* the vtable can do whatever ABI needs to make this work
* need an intrinsic to call a fn whose return type is `?Sized` and you supply the pointer where the result goes
* at monomorphization time, if return type is sized, this is just a regular call (`std::ptr::write(...)`)
* if it is unsized (e.g., dyn) we invoke the vtable method
* we do the right for `[T]` whtaever that is (memcpy?)
Are the idea of `&Trait` bounds important?
You write `dyn trait` on your trait and we enforce:
* it will add `impl<T> Trait for &T` and friends (not really needed, because we are passing a dynx now)
* you only use `impl Trait` with other dyn trait traits
* niko wants this for soundness
```rust=
trait MyTrait {
fn adapt(
&self,
x: impl(Box::pin) FnOnce(),
) -> impl Iterator<Item = u32>;
}
impl MyTrait for MyType {
fn adapt(
&self,
x: impl FnOnce(),
) -> impl(Box::pin) Iterator<Item = u32>;
}
```
* individual impls can't "fail" to produce a vtable
* would be a post-monomorphization failure
* but they could "panic" in
## 2021-12-06
tmandry `with` blog post draft: https://hackmd.io/LkzoeLaaQV2MMh512WSG7A?view
https://github.com/nikomatsakis/dyner/blob/main/src/dynerx.rs
### what is the "built in" story
* you will create a `dyner Trait` from some "pointer to T where T: Trait"
* "pointer" is anything that supports `into_raw` and `from_raw`
* e.g. could be `Box<T>` or `Rc<T>` or `&T` or `&mut T`
* `dyner Trait: Sized`
* `dyner Trait: Trait`
* but wait: for `Rc<T>` or `T`, you can only get `&self`
* for `&mut T`, can only get `&self` or `&mut self`
* for some traits, that's okay
* so `&'a T` can become a `dyner Debug + 'a`
* but for other traits, not so ok
* but a `&'a T` cannot be made into a `dyner Iterator`
* so what do we do?
* answer: introduce `&Trait` and `&mut Trait` bounds
* intuitively these are either "views" on to Trait that select a subset of methods
* or perhaps they are equivalent to `Deref<Target: Trait>` and `DerefMut<Target: Trait>`
* but in any case you can make a `dyner &Iterator` from `&T`
* whichever way:
* `dyner &Iterator: Deref<Target = dyner Iterator>`
* observation: `&dynx Debug` has "double indirection"
* if you have an `&impl Debug`, and you want to use it in dyn form *without* double indirection
* you could do `dyner Debug + Copy` (for this case)
impl/dynx symmetry:
```rust
fn foo(x: impl Debug) { }
// you can do `foo(22)` or `foo(&22)`
fn bar(x: dynx Debug) { }
// would like if you could do `bar(22)` or `bar(&22)`
// ^^^^^^^ but this requires some kind of "auto-ref"
```
observation:
each trait has a "natural pointer type"
* if only `&` or `*const`, then `&`
* if only `&mut` or `*mut`, then `&mut`
* else `Box`
```rust
fn foo(x: &impl Debug + ?Sized) {
bar(x)
}
fn bar<T: Debug>(x: &T) { ... }
```
Questions:
* How do you create a `dyner`? Coercion? Is there an explicit form?
* If the answer is coercion, what can you create a `dyner` from:
* from the pointer? (most explicit, need to have this option)
* from the pointee? (requires auto-ref of some kind)
* maybe sometimes one, sometimes the other?
If we limit ourselves to pointer, then, if you start with this code:
```rust
fn foo(x: impl Debug) { ... }
foo(22)
```
and you change `foo` to use `dyner`, you start to get errors:
```rust
fn foo(x: dyner Debug) { ... }
foo(22) // ERROR
```
arguably that is the wrong code, and what you wanted is
```rust
fn foo(x: impl Debug) {
bar(&x)
fn bar(x: dynx Debug) { ... }
}
foo(22) // ERROR
```
maybe we just want to make that more syntactically pleasant.
Niko's conclusions:
* Trying to make a super smart coercion will be a leaky abstraction and wind up both unsatisfying and confusing
* We need another mechanism to avoid monomorphization costs (e.g., dyn type parameters)
* We should have coercions *from* a pointer
* we might want an explicit form like `expr.dyner`, plausibly that could do auto-ref though
Challenge is that we sort of want a few constructors. Function of both the trait and the pointer.
| (pointer) | Trait has &self | Trait has &mut self | Other |
| --- | --- | --- | --- |
| `Box` | `Trait` | `Trait` | `Trait` |
| `&T` | `Trait` | `&Trait` | `&Trait` |
| `Rc<T>` | `Trait` | `&Trait` | `&Trait` |
| `&mut T` | `Trait` | `Trait` | `&mut Trait` |
The set of traits that the pointer must implement depends on the `Bounds` in `dyner Bounds`:
* Must always implement `IntoRaw` (a new trait afawk)
* If `Bounds` includes has an element with a `self: &Self` method:
* must implement `Deref`
* If `Bounds` includes has an element with a `self: &mut Self` method:
* must implement `DerefMut`
* If `Bounds` includes has an element with a `self` method:
* must implement `IntoInner` (a new trait afawk)
* or `DerefMove`
* If `Bounds` includes has an element with a `Box<Self>` method:
* must be `Box<?>`
* If `Bounds` includes has an element with `Pin<&Self>` method:
* must implement `Pinned` (where `Pinned` is an unsafe trait implemented by `Pin<P>`)
* must implement `Deref`
* If `Bounds` includes has an element with `Pin<&mut Self>` method:
* must implement `Pinned` (where `Pinned` is an unsafe trait implemented by `Pin<P>`)
* must implement `DerefMut`
* If `Bounds` includes has an element with `Pin<Box<Self>>` method:
* must implement `Pinned` (where `Pinned` is an unsafe trait implemented by `Pin<P>`)
* must implement `DerefMut`
* must be `Pin<Box<?>>`
less is more design:
* `dyn trait Trait`
* automatically provides the `impl Trait for &dyn Trait` impls
* automatically provides the `impl Trait for &mut dyn Trait` impls
* automatically provides the `impl Trait for Box<Trait>` impls
* errors if Trait is not dyn safe
* Question:
* how does it handle `-> impl Trait`?
* Answer: Trait must also be `dyn`
* the associated type for `dyn Trait` is hardcoded to `Box<Trait>`
* generates the vtable shim; we know that `Box<Trait>: Trait` because `dyn trait` guaranteed that
* how does it handle `impl Trait` in argument position
* Answer: Trait must also be dyn
* can invoke with `&x`/`&mut`/`Box::new` of the parameter depending:
* if the trait has only borrowing methods and does not require `'static`, can use `&` or `&mut`
* else must use `Box`
* what about `-> Self`? (notably `Clone`)
* uses `Box`
* final methods can be handled and have no restrictions
* or even defaulted -- we just say that the default is what gets invoked
* probably with some opt-in
* replaces `where Self: Sized`
### niko noodles post meeting
* challenging cases
* impl trait in APIT:
* in general case need something like `Box`
* how to make this "no-std compatible"
* what type does the thing in the vtable expect?
* something like the dyner version would be good
* it has a `*mut dyn Trait` and a vtable extension that lets it be dropped
* what about `-> Self`?
* we want to return the same type we got in -- well, probably?
* so if you have `Box<dyn Trait>` you want `Box<dyn Trait>` afterwards?
* is that true? I often have `&T` and I invoke clone to get `T`
* maybe with `&dyn Trait` I want `Box<dyn Trait>`
* then conceivably implement Clone for `&dyn Trait` where `Trait: Clone` that returns `Box<dyn Trait>`
* vtable would include a wrapper that
## 2021-12-02
https://dyner.netlify.app/faq#does-dyner-have-a-theme-song
[with clause post](https://hackmd.io/LkzoeLaaQV2MMh512WSG7A?view)
### Built-in `dyner`
What is dyner...
* you make a type `DynFoo` that represents a particular "configuration" of dynamic dispatch
* how to "box" `-> impl Trait`
* how to "box" the dyn value itself (if you do box it)
* this type encapsulates the pointer + the pointee (so it is sized)
* i,e., you don't do `Box<DynFoo>`, you just do `DynFoo` (or `&DynFoo` etc)
* if you make a `DynFoo` from an `&impl Foo` you get a `Ref<DynFoo>`, which only supports `Deref` trait
* side note: can prob get rid of that "bit twiddling" to track whether to free
* maybe in the future
* which functions to "devirtualize"
* instead of `where Self: Sized`, making a 'default' that runs
* ergonomic easy path
* possible other paths
```rust
dyn trait Foo {
}
```
```rust
dyn<Box> Foo
&dyn<Box> Foo
```
```rust
trait SomeTrait {
fn link(self: Rc<Self>);
}
x: Rc<dyn SomeTrait>
x.link();
x: exists<R: SomeTrait> Rc<Rc<R>>
x: dyn<R: SomeTrait> Rc<Rc<R>>
fn foo<dyn T: SomeTrait>(x: &T, y: &T) {
....
}
```
---
let's use virtual
```rust
virtual trait Foo {
}
let x: virtual Foo = Box::new(some_foo);
let x = DynFoo::boxed(some_foo);
let x = virtual Foo::boxed(some_foo);
let x = virtual some_foo;
fn foo(x: virtual FnMut<Item = u32>) {}
```
today I write:
```rust
foo(|| ...)
fn foo(x: impl FnMut<Item = u32>) {}
```
to make it dynamic today I have to add `&mut` both places
```rust
foo(&mut || ...)
fn foo(x: &mut dyn FnMut<Item = u32>) {}
```
this would be nicer..
```rust
foo(|| ...) // compiler autorefs
// foo(&mut || ...)
// relying on:
// &mut dyn FnMut<Item = u32>: dyn FnMut<Item = u32>
fn foo(x: dyn FnMut<Item = u32> + '_) {}
```
```rust
fn foo(x: impl Debug) {}
```
https://pol.is/report/r2p6mj8dka3kpsnymv6aj
https://rust-lang.github.io/async-fundamentals-initiative/evaluation/challenges/dyn_traits.html
https://rust-lang.github.io/async-fundamentals-initiative/design-discussions/dyn_trait.html
https://rust-lang.github.io/async-fundamentals-initiative/design-discussions/dyn_async_trait.html
```rust
fn foo(x: impl FnMut<Item = u32>) {
fn bar(x: &mut dyn FnMut<Item = u32>) { ... }
bar(&mux x)
}
```
```rust
trait VtableFoo {
fn vtable_foo(&mut self, x: DynRef<Item = u32>)
}
fn foo(&mut self, x: impl FnMut<Item = u32>) {
self.vtable_foo(DynRef::from_mut_ref(&mut x))
}
```
```rust
dynX Foo
dynX<Rc> Foo
&dynX<Rc> Foo
// Defaults to allocating a Box; erases that knowledge
let x: dynX Future = /*box*/ some_async_fn();
// Defaults to <unknown container>
fn foo(x: dynX Future) {}
// Can also support
fn foo(x: dynX<Rc> Future) {}
```
`dyn &Future`
`dyn &mut Future`
`&dyn &Future` => `&dyn Future`
`&mut dyn &mut Future` => `&mut dyn Future`
`dyn &Future: Deref<Target = dyn Future>`
```rust
trait MyCollection {
fn push(&mut self);
fn len(&self);
}
fn foo<T: &MyCollection>(t: T) { }
fn foo<T: Deref<Target: MyCollection>>(t: T) { }
dyn &mut Iterator<Item = u32>
X = dyn DerefMut<Target: Iterator<Item = u32>>
&mut X => &mut dyn Iterator<Item = u32>> // deref coercion
```
## 2021-11-29
### stakeholder meeting retrospective?
* publish minutes "as is" / or try to write a summary
* email people that we plan to, give them a chance to raise any concerns
* defer: write a blog post that tells about the lessons and experience and summarizes
* https://hackmd.io/SwLsaDDmTSCLKQfE2DYk1Q
### RPITIT / async fn
How Niko is thinking about things
#### Step -1
What is missing from the impl trait in traits RFC?
```rust
trait Iterator {
fn next(&mut self) -> Option<impl Sized>;
}
```
```rust
trait AsyncTrigger {
fn start(&mut self) -> impl Future<Output = ()>;
}
```
```rust=
fn foo(x: impl AsyncTrigger)
where
/* typeof x.start() */: Send, // <-- thing we want conceptually
x::start: Send, // <-- shorthand
for<'me> x::start<'me>: Send, // <-- longhand
{
tokio::task::spawn(async move {
x.start().await;
// type of x.start() is some "impl future"
});
}
```
#### Step 0
```rust
trait LendingIterator {
type Item<'me>;
fn next(&mut self) -> Self::Item<'me>;
}
impl<T> LendingIterator for Vec<T> {
type Item<'me> = &'me T;
// Error: not WF, `T: 'me` not known
fn next(&mut self) -> Self::Item<'me> {
self.iter()
}
}
```
#### Step 1
```rust
trait LendingIterator {
type Item<'me>
where
Self: 'me;
fn next(&mut self) -> Self::Item<'me>;
// ^^^^^^^^^ implied bound of Self: 'me
}
impl<T> LendingIterator for Vec<T> {
// compiles!
type Item<'me> = &'me T
where
Vec<T>: 'me; // => T: 'me
fn next(&mut self) -> Self::Item<'me> {
self.iter()
}
}
```
Status for GATs as of a few weeks ago:
* Algorithm for finding which where clauses ought to be included by default on GATs
* Current compromise:
* force user to write where clauses explicitly
* thus backwards compatible to make them appear by default OR make them not required
#### Step 2
```rust
trait LendingIterator {
fn next(&mut self) -> impl Sized + '_;
// desugars to:
fn next(&mut self) -> Self::next<'_>;
type next<'me>: Sized
where // <-- talk about impl details here
Self: 'me;
}
```
#### Step 3
```rust
trait LendingIterable {
fn iter(&self) -> impl LendingIterator + '_;
}
```
But what if you want to know "what kind of item is going to be producted by the iterable that iter returns"... `IntoIterator` has `IntoIter` (type of iterator that is produced) and `Item` (type of item yielded by that iterator).
```rust
trait Iterable {
final type Item<'me> =
Self::iter<'me>::Item; // <-- error!
fn iter(&self) -> impl Iterator + '_;
}
impl<A: Debug> Iterable for A {
default type Item<'me> = ...;
// if there is no specializing impl, then ITem will be this
fn iter(&self) -> impl Iterator + '_;
}
```
#### Step 3.5
```rust
trait Iterable {
final type Item<'me> = Self::iter<'me>::Item
where
Self: 'me;
fn iter(&self) -> impl Iterator + '_;
// implied bound: where Self: '_
}
```
#### Step 4
```rust
struct MustBeEq<T: Eq>(T);
// no error:
type Foo<T> = MustBeEq<T>;
// use it with something that is not Eq, I get an error at that point
```
```rust
struct MustBeEq<T: Eq>(T);
type Foo<T> where T: Ord = MustBeEq<T>;
// ^^^^^^^^^^^^ unenforced
```
```rust
struct MustBeEq<T: Eq>(T);
type Foo<T> = MustBeEq<T>
where // <-- default
MustBeEq<T>: OK;
// in libcore
trait OK { }
impl<T: ?Sized> OK for T { }
```
#### Step 5
```rust
trait Iterable {
final type Item<'me> =
Self::iter<'me>::Item;
// compiler default:
// where Self::iter<'me>::Item: OK
// from which we can infer that Self: 'me
fn iter(&self) -> impl Iterator + '_;
// desugars to:
fn iter(&self) -> Self::iter<'_>;
type iter<'me>
where
&'me Self: OK; // => Self: 'me
}
```
What does this need?
* OK trait and our handling of WF would have to be tweaked
* callee gets to assume its where clauses are well formed
* not just its input arguments
* tweak to "implied bounds"
```rust=
struct Foo<'me, T>(&'me T);
// inferred where clausE: where T: 'me
fn bar<'me, T>()
where
Foo<'me, T>: OK
{
// Today: error unless you add
// where T: 'me
//
// Under Niko's proposal above: compiles fine
}
```
```rust
struct Foo<T: Eq> { }
// T: Eq => Foo<T> WF
//
// can I say the other direction?
//
// Foo<T> WF => T: Eq -- semver question
//
// but we would add the `=>` direction for outlives bounds, so that's a little wacky
```
#### foo
```rust=
fn foo<'a, T>(x: &'a T) -> impl Sized
where
T: Foo<'a>,
{
}
type Foo<'a, T> = impl Sized
where
T: Foo<'a> // <-- weird;
// T: Foo<'static> // not true
fn foo<'a, T>(x: &'a T) -> Foo<'static, T>
where
T: Foo<'a>,
{
}
type Foo<'a, 'b, T> = impl Sized
where
T: Foo<'a> // <-- weird;
// T: Foo<'static> // not true
fn foo<'a, T, 'b>(....) -> Foo<'static, 'b, T>
where
T: Foo<'a>,
{
}
```
###
```rust
trait LendingIterable {
final type Item<'me> = Self::iter<'me>::Item
/* implied: where Self::iter<'me>::Item: OK */
;
fn iter(&self) -> impl LendingIterator + '_;
}
```
### existential lifetimes in impl trait
https://github.com/rust-lang/rust/issues/60670
### with types?
## 2021-11-19
### Stakeholders retrospective
* Call on people to give feedback
* Got a little sidetracked
* Need to talk about overall roadmap
## 2021-11-18
* [ ] Stakeholder meeting
* [ ] "dyn adaptation"
* [ ] Can we make it implementable by macros outside the crate defining the trait?
* [ ] What's the ergonomic path?
* [ ] `dynX` idea
* [ ] What are the problems facing it?
* [ ] Idea for conditional bounds (Niko)
* [ ] How to help
* [Stakeholder explainer](https://hackmd.io/_fnM79SsSIWo86bdZXuNPw)
* `DynTrait<'lt>`
* before: this always encloses a `Box`
* after:
* can initialize from box
* or from &T or &mut T
* and can avoid giving access to the methods that would not be accessible in the latter case
---
```rust
trait Foo {
fn foo(&self) -> impl Debug;
}
trait Foo {
type foo<'me>: Debug;
fn foo(&self) -> Self::foo<'me>;
}
impl Foo for Bar {
// because foo was declared in trait as RPITIT...
fn foo(&self) -> XXX { }
// ...it becomes...
type foo<'me> = XXX;
fn foo(&self) -> Self::foo<'me> {
// so you don't have to put impl trait if you don't want to
}
}
fn method<T>()
where
T: Foo<foo: Send>,
for<'a> T: Foo<foo<'a>: Send>
T: Foo<foo<..>: Send>,
// ^^^^
```
* `'_` in where clause == forall
* turbofish rules for these GATs:
* if there are APIT, cannot use turbofish
* if you do not supply any lifetimes: use `'_` for all of them
* if you *do*, there cannot be any late-bound lifetimes (else error) (this rule isn't actually needed for this idea)
* else must supply all
* must supply all type parameters
* for other GATs:
```rust
struct Foo<T: FnOnce()> { }
struct Foo<T: FnOnce(), const F: T> { }
impl<T: FnOnce(), const F: T> Foo<T, F> {
fn foo() {
F();
}
}
```
```rust
const fn<T: FnOnce(C), C>(f: T) -> fn(C) {
assert!(sizeof::<T>() == 0);
}
const fn<T: FnOnce(C)>(const f: T) -> fn(C) {
assert!(sizeof::<T>() == 0);
}
// "Non-stateful closure"
```
---
```rust
struct Ref<T> { t: T }
impl<T> Deref for Ref<T> {
type Target = T;
fn deref(&self) -> &T {
&self.t
}
}
struct RefMut<T> { t: T }
impl<T> Deref for RefMut<T> {
type Target = T;
fn deref(&self) -> &T {
&self.t
}
}
impl<T> DerefMut for RefMut<T> {
fn deref_mut(&mut self) -> &T {
&mut self.t
}
}
```
```rust
type DynTraitRef<'lt> = Shared<DynTrait<'lt>>;
struct Custom<T> { t: T }
impl<T> Deref for Custom<'lt, T>
where
T: Deref,
T::Target:
{
type Target = DynTrait<'lt>;
fn deref(&self) -> &T {
&*self.t
}
}
impl DynTrait<'lt> {
fn boxed<T>(x: T) -> DynTrait<'lt>
where
T: Trait,
{
}
fn from_ref<T>(x: &'lt T) -> Ref<DynTrait<'lt>>
where
T: Trait,
{
}
fn from_mut<T>(x: &'lt mut T) -> Mut<DynTrait<'lt>>
where
T: Trait,
{
}
fn from_mut<T>(x: T) -> Custom<DynTrait<'lt>>
where
T: Deref,
T::Target: Trait,
{
}
}
```
```rust
fn foo(x: &DynTrait<'_>) {
}
fn bar() {
let y = ...;
let x = DynTrait::from_shared(&y);
foo(&x)
}
```
## 2021-11-15
* [Niko wrote some stuff](https://hackmd.io/78T_K20VQVe-vBxBWWuUlw)
* Bridging [poll traits](https://docs.rs/hyper/0.14.14/hyper/body/trait.HttpBody.html) with async traits
* Hard with multiple poll functions
* Something something resume args ((with?))
* Easier with single poll: inline async fn
## 2021-11-11
* [x] WIP updates
* [x] dyn conversation
* [x] implementation
* [ ] Stakeholder meeting
* [ ] "dyn adaptation"
* [ ] Can we make it implementable by macros outside the crate defining the trait?
* [ ] What's the ergonomic path?
* [ ] `dynX` idea
* [ ] What are the problems facing it?
* [ ] Idea for conditional bounds (Niko)
* [ ] How to help
### Action items
* (Niko by Monday) Turn outline into something for the repo
* (Spastorino by Monday) "code"
* Future: Writing up issues for things like inline etc.
### Notes
* Going to pursue RPITIT to start
* what we will ship
* stage 0
* stable compiler supports impl Trait and GATs
* stage 1
* stable compiler can compile async fn in traits
* no dyn
* crate published by rust-lang available on crates.io for dynamic dispatch
* dyner
* `#[dyner] trait Foo { }` creates `DynFoo::new(...)` that implements `Foo`
* supports:
* traits with async fn
* traits with `-> impl Trait` if `dyner` is used on Trait (maybe?)
* traits with `(impl Trait)` if `dyner` is used on Trait (maybe?)
* includes:
* "Dyner"-ified versions of libstd traits like AsyncRead and friends
* stage 2
* libstd will add stable versions of
* AsyncRead, AsyncWrite, AsyncStream
* (domain of the portability initiative)
* stage 3 and beyond
* based on experience with dyner we figure out an official dyn story
* "Someone is coding with dyner... :musical_note::musical_note::musical_note:"
* async closures
* other fun stuff
* what can you do with this
* Grace and Alan are hacking on their async rust service at SomeBigCo
* Traits they use internally just use async fn
* If they want dyn dispatch, they use `#[dyner]`
* To talk about read/write traits, they use the dyn-ified versions from dyner
* Barbara has a cool idea for an arena-ified alternative (or one that caches .. or something .. )
* she forks dyner and writes her own punny named crate that embodies this pattern
* she submits the link to the repo
* it's collected and in the doc and when the async fundamentals team gets to stage 3 they use a variation of this brilliant idea in their final design
* Grace is working on her embedded project, she can use the stable async fn support to get static dispatch
* She has a plan for dyn dispatch and experiments and publishes her own procedural macro crate which the async fundamentals group adds to their repo
* Opens a PR with an experimental of version of embedded-dyner
* Hyper publishes a "hyper-dyner" crate that includes dyn-ified versions of its traits
* or maybe Sean Monstar opts for a feature flag. Whatever dude. You do you.
* Niko's wild and crazy Rust 2024 fantasies
* "feature previously known as dyn" => low-level primitive, maybe it is even replaced with existential types or something
* observation: if dyn is a low-level primitive, "dyn-safe" is silly, you want to expose as many capabilities as you can
* "low-level"? not the thing most code reaches for first
* sort of like `for<'a>`
* you have `dyn trait Foo` that exposes some "pretty useful" version (probably with Box) that is ergonomic and good enough most of the time
* ability to declare your own variations in other crates (with traits you didn't define and don't have to copy and paste) and use those
* you have "existential types" (which replace today's `dyn`) as the "fancy version" to build those nicer, ergonomic versions with
* and for scala refugees
* "inline async at impl site" ??
* don't recurse!!!
* add in a panic at runtime
*
## 2021-11-07
* [x] WIP updates
* [x] RFC
* [x] Stakeholders
* [x] Implementation
* [x] Syntax for named fn types
* [ ] "dyn adaptation"
* [ ] Can we make it implementable by macros outside the crate defining the trait?
* [ ] What's the ergonomic path?
* [ ] `dynX` idea
* [ ] What are the problems facing it?
* [ ] Idea for conditional bounds (Niko)
* [ ] How to help
### WIP updates
#### RFC
* Should we talk to cramertj?
* Responded in [comments](https://github.com/rust-lang/rfcs/pull/3185#issuecomment-961499403)
#### Stakeholders
Looking at https://alternativeto.net/software/doodle/
#### Implementation
Can use `type $ = impl Foo;` to implement RPITIT, and then implement `async fn` desugaring in terms of that.
### Syntax for named fn types
* It would be nice to have explicit and anonymous generics be equivalent
* but it doesn't seem to work very nicely
* you need `decltype` and then `declval`
* We can make anonymous generics late-bound
* Hopefully explicit generics too, eventually
* Still need to support `let f = foo::<i32>;`
* Requires making some "wrapper" to hold the specified generics. i.e. type currying
## 2021-11-03
* [x] WIP updates
* [x] RFC
* [x] Implementation
* [ ] Niko's dyn idea
* [ ] Syntax for named fn types
### RFC conversation
[cramertj comment](https://github.com/rust-lang/rfcs/pull/3185#issuecomment-956430290)
Will we be able to do this in the future?
Can libs assume it will be possible in the future? Backcompat hazard...
```rust
trait Foo {
async fn bar(&self);
}
// Right now RFC doesn't allow this...
impl Foo for u32 {
fn bar(&self) -> impl Future<Output = ()> + '_ {}
// only `async fn bar() {}` allowed
}
// But if I'm writing a lib..
```
### Implementation
```rust
async fn foo() {}
// Lowers to...
type Foo = impl Future<Output = ()>;
trait Foo {
async fn bar(&self);
}
// Lowers to...
trait Foo {
type __Foo<'a> = impl Future<Output = ()> + 'a;
fn bar(&self) -> __Foo<'a>;
}
// But in the future we want...
// (almost exactly what standalone functions do)
trait Foo {
fn bar(&self) -> impl Future<Output = ()> + '_;
}
// ..which then lowers to something like the above
```
Maybe faster to implement RPITIT first.
https://github.com/rust-lang/impl-trait-initiative
https://rust-lang.github.io/impl-trait-initiative/updates/2021-oct.html#type-alias-impl-trait-stabilization
```rust
trait Foo {
fn foo() -> impl Send;
}
```
## 2021-11-01
* [x] New sprint goals review
* [x] Stakeholder agenda
* [ ] Niko's dyn idea
* and another idea for conditional bounds
* [ ] Syntax for named fn types?
### Sprint goals review
* Get [MVP RFC](https://github.com/rust-lang/rfcs/pull/3185) to FCP
* Niko [fcp merged](https://github.com/rust-lang/rfcs/pull/3185#issuecomment-956370267)
* Implementation:
* Santiago has done a basic desugaring but tests are failing still
### Stakeholder meeting agenda
* 90 minutes
* Who will present? tmandry mostly
* Outline
* Format
* We'll talk
* You ask questions whenever they come up, no need to wait
* Async vision doc overview (keep it short)
* The grand [roadmap]:
* Scoped APIs for reliable concurrency
* Common interop traits are just "async fn"
* Our part today:
* The very first step
* Other active initiatives:
* Generators async and otherwise
* Tooling (tokio console, crashdumps)
* Polish (the bug! backtraces!)
* What does async fn in traits mean
* Async fn: fn that returns impl Future
* impl Trait in traits desugars to associated type
* Send bounds and named return types
* The syntax we expect
* Where would this be needed
* Feedback point:
* What have your experiences been with Send bounds in generic code so far?
* Do your codebases frequently use `spawn` or other parallel operations?
* This is the MVP:
* You can write async fn in traits
* It works in static cases
* Writing the Send bounds for futures is kinda painful but possible
* Major capability missing: dynamic dispatch
* Associated type prevents dynamic dispatch
* Also, boxing
* Not sure the most general fix here
* Current approach:
* procedural macro
* Feedback point:
* Where do you use dyn dispatch vs static in your codebases?
* Shortcomings of MVP and future work
* Dynamic dispatch in the lang
* Shorthands or better ways to put send bounds
* Multiplication bounds (!)
* Globs
* Implementation status
* Core features are on path to stabilization
* Async sugar is on its way to nightly
* We'll let you know when it's time to port your code to try this out and give instructions for how to do it
[roadmap]: https://rust-lang.github.io/wg-async-foundations/vision/roadmap.html
### Niko's crazy dyn idea
* `dynx Trait`
* "A pointer to `Trait` that implements `Trait`"
* whereas:
* `dyn Trait` = `exists T. Implemented(T: Trait)`
* whereas:
* `dynX Trait` = `exists T. sizeof(T) == sizeof(usize) && Implemented(T: Trait)`
* probably want to combine this with:
* `impl<T, U> Trait for T where T: Deref<Target = U>, U: Trait` -- automatic for traits with only `&self` methods
* `impl<T, U> Trait for T where T: DerefMut<Target = U>, U: Trait` -- automatic for traits with only `&mut self` and `&self` methods
* `impl<T: Trait> Trait for Box<T>` -- always true
* just imagine this is true for now
* what does this mean?
* `Box<dyn Iterator>` == `dynx Iterator + 'static`
* `Rc<dyn Debug>` == `dynx Debug + Clone + 'static`
* `&'a dyn Debug` == `dynx Debug + Copy + 'a`
* for any dyn safe trait `Trait`
```rust
trait MyTrait {
fn foo(x: impl OtherTrait) {
// we know that `x` does not escape this function
// without being tracked, because `x` could be a `&T`
}
}
```
we want `MyTrait` to be dyn safe, but we can't put `foo` into the vtable because it requires monomorphization
because we know that `&T: OtherTrait` where `T: OtherTrait`, however, we could put this in the vtable:
```rust
fn vtable_foo(x: dynx Trait) {
...
}
```
and then in the `impl MyTrait for dynx MyTrait` impl use this function:
```rust
impl MYTrait for dynx MyTrait {
fn foo(x: impl Trait) {
vtable_foo(&x)
}
}
```
Of course, this doesn't really require `dynx`. You could do same transformation with `dyn`, if you know that `&T: Trait` where `T: Trait`. You put this in the vtable:
```rust
fn vtable_foo(x: &dyn Trait) {
...
}
```
and this in the `impl MyTrait for dyn MyTrait`:
```rust
// shim user calls:
fn foo(x: impl Trait) {
vtable_foo(&x)
}
```
### Step back and just talk about dyn and erased serde
```rust
trait MyTrait {
fn foo(x: impl OtherTrait);
}
trait OtherTrait {
fn bar(&self);
}
impl<T> OtherTrait for &T
where
T: ?Sized + OtherTrait
{
fn bar(&self) {
T::bar(self)
}
}
```
What could we do?
We could write:
```rust
trait DynMyTrait {
fn dyn_foo(x: &dyn OtherTrait);
}
impl<T> DynMyTrait for T
where
T: MyTrait,
{
fn dyn_foo(&self, x: &dyn OtherTrait) {
<T::foo as FnOnce(&dyn OtherTrait)>::call_once(self, x)
// ^^^^^^^^^^^^^^^
// type given to the impl trait
}
}
```
The final "knot" is that one can implement
```rust
impl MyTrait for dyn DynMyTrait {
fn foo(&self, x: impl OtherTrait) {
let x = &x as &dyn OtherTrait;
// ^^^^^^^^^^^^^^^
// Possible because `OtherTrait` is dyn safe
self.dyn_foo(x)
}
}
```
Using all these pieces, if you have a `&T: MyTrait`, you can ...
* convert the `&T` to `&dyn DynMyTrait`
* convert the `&'a dyn DynMyTrait` to `impl MyTrait + 'a`
* not that useful
*
## 2021-10-27
* Syntax for named function types
* https://hackmd.io/WQUfas2jSiaeIv6EBPgtew
* Plan around dynamic dispatch
* Stakeholder meeting, agenda plan?
* Next steps for dyn
* `with` clauses?
### Late-bound and arguments
```rust
trait Foo {
async fn bar(&self, x: impl Debug);
}
```
```rust
fn my_helper<T: Foo>
where
T::*::Output: Send
<T as Foo>::fn::bar::Output: Send
for<D: Debug + Send> { <<T as Foo>::fn::bar as FnOnce(&T, D)>::Output: Send }
<<T as Foo>::fn::bar as FnOnce(&T, impl Debug + Send)>::Output: Send,
```
```rust
trait Foo {
async fn bar(&self);
}
```
```rust
fn my_helper<T: Foo>
where
T::fn::bar::Output: Send, // <-- what you write
// ^^ look ma, no args -- works for elided lifetime parameters
for<'me> { <<T as Foo>::fn::bar as FnOnce(&'me T)>::Output: Send }, // <-- what it means
// ^^^^^^^^ defaulting the arguments
// from the signature of `fn bar`
// and substituting the `Self` or
// other trait parameters
where
T::Item // <T as Iterator>::Item -- T is the Self type
```
### Stakeholder meeting
* Explain the plan
* Concept of MVP
* MVP
* Dyn async fn in traits
* using a proc macro to generate a wrapper struct
* Naming of output types
* Feedback in meeting
* How often do you think you will want dyn vs static dispatch?
* Feedback after trying it
* Naming output types and
### Dyn async fn
High-level idea
```rust
trait Foo {
fn stuff(&self);
}
// Compiler generates:
impl Foo for dyn Foo {
fn stuff(&self) {
self.vtable[0](self);
}
}
trait Bar {
async fn stuff(&self);
}
impl Bar for dyn Bar {
// Post-desugaring
type __stuff_output<'a> = Pin<Box<dyn Future<Output = ()>>> + 'a;
fn stuff<'a>(&self) -> Pin<Box<dyn Future<Output = ()>>> + 'a {}
}
impl dyn Bar {
fn stuff(&self, arena: &Arena<'a>) -> Pin<ArenaBox<'a, dyn Future<Output = ()>>> {}
}
```
###
## 2021-10-25
```rust
// Warning: For reasons we are in the midst of explaining,
// this version of the trait will not compile.
trait Iterable {
type Item<'me>;
type Iterator<'me>: Iterator<Item = Self::Item<'me>>;
fn iter<'a>(&'a self) -> Self::Iterator<'a>;
}
impl Iterable for Vec<T> {
type Item<'me> = &'me T; // <-- Error: don't know that T: 'me
type Iterator<'me> = std::vec::Iter<'me, T>;
fn iter(&self) -> Self::Iterator<'_> { self.iter() }
}
```
What we want:
```rust
trait Iterable {
type Item<'me>
where
Self: 'me;
type Iterator<'me>: Iterator<Item = Self::Item<'me>>
where
Self: 'me;
fn iter<'a>(&'a self) -> Self::Iterator<'a>;
}
impl Iterable for Vec<T> {
type Item<'me> = &'me T where Self: 'me;
// Self = Vec<T>
// Vec<T>: 'me => T: 'me
type Iterator<'me> = std::vec::Iter<'me, T> where Self: 'me;
fn iter(&self) -> Self::Iterator<'_> { self.iter() }
}
```
Current status of GATs, doing an analysis of the trait def'n to find missing where clauses:
* For every GAT `G` in a trait definition with generic parameters `X0...Xn` from the trait and `Xn..Xm` on the GAT... (e.g., `Item` or `Iterable`, in the case of `Iterable`, with generic parameters `[Self]` from the trait and `['me]` from the GAT)
* If for every method in the trait... (e.g., `iter`, in the case of `Iterable`)
* When the method signature (argument types, return type, where clauses) references `G` like `<P0 as Trait<P1..Pn>>::G<Pn..Pm>` (e.g., `<Self as Iterable>::Iterator<'a>`, in the `iter` method, where `P0 = Self` and `P1` = `'a`)...
* we can show that `Pi: Pj` for two parameters on the reference to `G` (e.g., `Self: 'a`, in our example)
* then the GAT must have `Xi: Xj` in its where clause list in the trait (e.g., `Self: 'me`).
How we desugar RPIT today:
```rust
fn foo<'a>(x: &'a u32) -> impl Debug + 'a {
}
fn foo<'a, T>(x: &'a u32) -> Foo<T, 'a> {
type Foo<T, 'me> = impl Debug + 'me; // scope of this is the enclosing fn
}
```
```rust
trait Iterable {
fn iter(&self) -> impl Iterator + '_;
// "desugared"
fn iter(&self) -> impl Iterator + '_
type Iter<'me>; // inherits the where clauses
}
```
### Tests
Things to add
- Generic async fn
- with where clauses req'd to type check
- Elided lifetimes in async fn
### Impl notes
* `async fn` -> return position `impl Trait` -> associated type
* Be careful about elided lifetimes
* May or may not be easier to start with a nameable associated type
* `gensym`?
* Ask petrochenkov how to do it
* Check what argument position impl trait does
## 2021-10-20
* [RFC Draft](https://hackmd.io/ZKb-lh8iRN66RiuYjALZrA)
* tmandry to upload to repo
* and open a PR to rust-lang/rfcs
* Milestones
* Santiago to make a list of tests for desired behavior
* read the RFC
* Tyler/Niko review list of tests and add anything that seems to be missing
* Santiago to write tests for desired behavior
* Naive desugaring for async fn in traits/impls
* literally introduce an associated type with the same name as the method but with `Output` appended?
* Niko to open RFC for `-> impl Trait` in traits
* Implement `-> impl Trait` in traits properly
* Implement the dyn procedural macro "stuff"
* Ergo-dyn milestones (dyno)
* Open issues on the repository
* Encourage people to do it
* [find a new name](https://www.thefreedictionary.com/words-that-start-with-din)
* dyner
### When would you want to use dyn anyway?
* Parser combinator library
* every combinator returns `Box<dyn Parser>` or whatever
* In async, passing around a `dyn AsyncRead` or whatever
* In sync, passing around a `dyn Read`
* Things you lose access to:
* Associated constants
* Static methods, constructors
* Kinds of traits:
* Traits where all methods are `&self`; ideally `Trait` would be implemented for `&Trait`
* Traits where all methods are `&mut self`
* Traits where methods are `self`
* In general, `Trait` should be implemented for `Box<Trait>`
* In general, `Trait` should be implemented for `Box<Trait>`
* Properties of `Box` that we need?
Something Niko likes is that you can have an `&dyn Debug` and call it without forcing any allocation
```rust
fn bar() {
debuglog(&22)
}
fn debuglog(x: &dyn Debug) {
}
```
```rust=
fn map<T>(x: impl Iterator<Item = T>) {}
fn main() {
}
```
Homework:
* Try to write up some example programs and the ergonomic nits that result
## 2021-10-18
* What does the MVP story look like?
* You can write async fn in traits/impls but not dyn saf†e
* You can't name the resulting future (until we get fn type syntax)
* but you can make an explicit associated type if you so choose
* There is a procedural macro available `#[ergo_dyn]` that a `DynTrait` struct that encapsulates a `Box<dyn Trait>` and supports async dispatch, impl trait in traits, and other nifty features
* If you could declare "cannot be overridden" defaults...
```rust
trait AsyncIter {
final type NextFuture<'me> = <Self as AsyncIter>::next_future::Output;
async fn next_future(&mut self) -> ...;
}
```
if you had that option, one could write a decorator to make it convenient
```rust
trait AsyncIter {
#[return_type(NextFuture)]
async fn next_future(&mut self) -> ...;
}
```
* What do we want feedback on from the stakeholders?
* Do you need dyn? If so, what are the details of how you plan to use it?
* Present two crates that let you easily swap back and forth
* Can people land the one version?
* What problems do they encounter?
* After you try it:
* Do you need Send bounds?
* Can you measure performance impact?
* MVP timeline and requirements:
* Nightly version
* Test suite
* Implement the sugar
* Procedural macros
* Stabilize TAIT -- EOY was my goal, but I'm not sure we're going to make it
* Stabilize GAT
[Named function types](https://rust-lang.github.io/impl-trait-initiative/RFCs/named-function-types.html)
[impl trait in traits](https://rust-lang.github.io/impl-trait-initiative/RFCs/rpit-in-traits.html)
### Late-bound lifetimes
```rust
fn foo<T>(x: impl Iterator<Item = T>) {
}
fn bar<T>(x: impl Iterator<Item = u32>) {}
fn main() {
let x: Foo<?, ?> = foo; // ERROR today
foo(...);
}
struct MyStruct {
f: foo<u32, x: vec::IntoIter<u32>> // conceptually
}
```
```rust
trait Foo {
async fn bar<U>(&mut self);
}
// <T as Foo>::bar<u32>::Output
//
// desugared to...something like this...
//
// for<'a> <<T as Foo>::bar<'a, u32> as FnOnce>::Output
```
### Argument types
`Foo<..>` // means the fn type
let's call this U
`<U as FnOnce<(A1, A2)>>::Output`
```rust=
let x: FnDef[Foo]<?X, ?Y> = foo;
impl<'a, A2> FnOnce<(&'a mut Self, A2)> for FnDef[Foo]<&'a mut Self, A2> {
type Output = SomeFutureType<'a>;
}
```
### Can we ... think of `impl Trait` as late-bound?
// given the fn foo from line 62
```rust
struct MyStruct {
field: foo<u32> // incomplete type
// conceptually:
//
// for<T> { foo<u32, T> }
//
// Foo<u32> // FnDef just doesn't have a value here
}
```
Rule: You need to name all the named type parameters, the rest are all late bound.
- Already the case that elided lifetime parameters are always late bound.
- For `impl Trait`, when it's called we're just doing `FnOnce` trait selection with the concrete type of that argument. No need to have a different function type for each instantiation.
## 2021-10-13
### with
* `with(x: T)` is a where clause
* dyn trait
* bounded clauses
* `in('a) { T: Trait }`
* in the future, would be the default `in('_) { ... }`
* "needs to be true independently of the scope I'm in "
* `in('static) { T: Trait }`
* `Implemented(T: Trait for 'a)`
* other use cases:
* [safer transmute](https://github.com/jswrenn/rfcs/blob/af9f3012de8a642a9fcaa2f2f334e68f682742ad/text/0000-safer-transmute.md)
* crate-local impls (sort of)
* maybe not a real use case
* implication types
* `P => T`
* `with(tokio: &mut TokioRuntime) => Box<dyn xxx>`
* other use cases:
* `for<'a, 'b> fn(&'a &'b u32, &'a u32, &'b u32)`
* unsound because of https://github.com/rust-lang/rust/issues/25860
* could upcast `for<'a, 'b> fn(&'static &'static u32, &'a u32, &'b u32)`
* `for<'a, 'b> ('b: 'a => fn(&'a &'b u32, &'a u32, &'b u32))`
* `for<'a, 'b where 'b: 'a> fn...`
* borrow checker integration
* I think what happens is that when you prove a predicate you get back a set of in-scope variables that are required
* much like today you get back lifetime bounds
```rust
struct Foo {
}
impl Foo {
fn foo(&mut self)
where
with(f: &mut Foo)
{
// self != f
}
}
fn main() {
let mut f = Foo { };
with(f: &mut f) {
f.foo(); // Error!
}
let mut f = Foo { };
let mut g = Foo { };
with(f: &mut f) {
let f1 = &mut f;
g.foo(); // Error!
drop(f1);
}
}
```
* async live over yield question
* are `with` live over await? interesting question
can express both patterns
```rust
// acts like a fn param
fn foo<'a>(...) -> impl Future + 'a
where in('a) { with(x: &mut Context) }
{
}
fn foo<'a>(...) -> impl with(x: &mut Context) => Future
{
}
```
* specialization
* specializing impls can't add with clauses
```rust
trait MyTrait { fn method(&self) { } }
impl<T> MyTrait for T { }
fn foo<A>(a: A) {
MyTrait::method(&a)
}
impl<T> MyTrait for T
where
with(cx: &mut Foo)
{
}
// in another crate
fn bar() {
foo(); // do I consider `cx` borrowed or not?
}
```
* optional / defaulted with clauses
* providing something that is `Copy` (e.g. shared ref) means can be used multiple times
`Box<dyn Foo + 'a>`
`Box<dyn with(cx: &mut Context) => Foo>`
`trait WithContext = with(cx: &mutContext>`
`trait WithContext<predicate P> = with(cx: &mutContext> P`
* complicaiton:
* how do you think about bounds on a struct type?
* `struct Foo<T: Debug>`
* what is the bound here?
### talking about dyn
```rust=
trait Foo { // would be nice if this were dyn safe
fn foo(x: impl Iterator<Item = u32>) {
}
}
fn foo(x: &move dyn Iterator<Item = u32>) { }
```
## 2021-10-06
- What about threading local arena through?
- This design shouldn't add more complications to that
```rust
impl<A: Allocator> Foo for dyn Foo
with(a: A) {
...
}
with(alloc: impl Allocator);
```
https://github.com/rust-lang/rfcs/pull/2492
```rust
impl<'a> Foo<'a> for String { .. }
impl Foo for String {
fn method<'a>()
}
```
```rust
impl Context {
fn stuff(&self) -> &Output;
}
```
```rust
// crate A:
trait SomeTrait {
fn method(&self);
}
// crate B:
struct Context { }
struct X;
impl SomeTrait for X
with<'a>(cx: &'a mut Context)
{
fn method(&self)
// can't write it here:
// with(cx: &mut Context)
{
}
}
```
```rust
with(value: Type) {
... can use value ...
foo();
}
```
```rust
with(cx: &mut Context)
with(cx2: &mut Context2)
```
```rust
with(cx: .., cx2: ...) {
}
```
## 2021-10-04
### Niko muses about dyn
```rust
trait Foo {
fn method(&self) -> impl Iterator<Item = ...>;
}
impl Foo for Blah {
fn method(&self) -> impl Iterator<Item = ...> {
... /* call the type of this X */
}
}
```
* given an instance `x: X` (`let x = <Blah as Foo>::method`)
* `x as fn(&Blah) -> XXX`
* trait `InstantiateFn<F> { ... }`
* `x: InstantiateFn<fn(&Blah) -> XXX>`
* Resolves to pointer to impl method
* `x: InstantiateFn<fn(&Blah) -> Box<dyn Iterator<Item = ...>>`
* Resolves to pointer to wrapper fn around impl method
* given this, you can write generic code that generates a vtable
* has to run at compilation time: need const fn
* you can also write a `impl Foo for dyn Foo` that consumes the vtable
### Impl question
Parent of a HIR node?
https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.find_parent_node
### Pieces
* MVP
* Ability to get type of a fn item
* fallback syntax to name items
* what about constants?
* for now we should make them an error to leave space for future expansion
* Ability to construct dyn vtables and implement dyn manually
* (Maybe) trait aliases
```
MyTraitSend!(X) ==> X: Send + X::foo: Send
trait MyTraitSend =
MyTrait + Send +
<Self as MyTrait>::foo: Send +
Bar: Send
X: MyTraitSend
trait Foo<T> where T: Ord =
Bar where T: PartialOrd
impl SomeTrait for X {
// Today:
// What Niko always types
type Foo<T>
where
T: Ord +
T: Send +
T: Blah
= Bar;
// What Niko always types
type Foo<T> = Bar
where
T: Ord +
T: Send +
T: Blah;
}
trait Foo<T> = where T: PartialEq<Self>
trait Foo<T> = T: PartialEq<Self>
X: Foo<T> => T: PartialEq<X>
(): Foo<T> "write an arbitrary predicate with no self"
```
Next: Arenas
### Sprint items
* Stakeholders
* Niko found 2 in AWS
*
* MVP RFC
* needs work
* create a hackmd and write it together
* Evaluation for the output type naming (niko will call it impl trait)
* needs work
* sort of belongs in the impl trait initiative
* create a hackmd and write it together
```rust
trait Foo {
async fn bar();
async fn baz();
}
type AllFooFutures<T: Foo> =
(<T as Foo>::bar::Output, <T as Foo>::baz::Output);
T: Foo + Send
where AllFooFutures<T>: Send
where T: FooSend // trait alias for the above
```
## 2021-09-30
* Async stakeholders plan: [link](https://hackmd.io/y31gA3ElSu2DUdY6vUGs8A)
* Possible stakeholders
* Web services: Niko has contacts in AWS
* Embedded Rust: Dario
* Web framework author:
* Web framework consumer:
* High-performance computing: glommio author
* Sourcing
* Dario
* Alice Rhyl
* Glauber Costa (glommio)
* farnz / Simon Farnsworth
* Android (BT?)
* Fuchsia (BT?) - Marie
* AWS people x 2 -- agreed
* Yosh
---
* dyn for any trait
* do not have to specify the associated types (ever)
* maybe you can emit elide the other trait parameters
* but:
* you can only directly use members that meet the safety criteria for your dyn type
* they can't name associated types whose values you don't know
* they can't reference the generics whose values you don't know (including Self), at least not in contravariant positions
* and then:
* dyn trait Foo
* implements the Foo for dyn Foo impl in a particular way
* can give an error if that can't be done
* and you can give hints on methods (maybe?) to configure it a bit
* another part:
* what do we need to allow people to implement the dyn impl (unsafely) and what do we need (safely)
* goodies that extend what is dyn safe a little bit
* mapping `impl Trait` return types (or associated types) for dyn safe traits to `Box<dyn>` and allocating
* impl trait in argument position ===> pass dyn by value? maybe Boxed?
[impl trait in traits brainstorming doc](https://hackmd.io/IISsYc0fTGSSm2MiMqby4A)
```rust=
trait Foo {
fn method(&self);
}
fn fun<T: Foo>(x: T) where T::method<'_>::Output: Clone {}
```
* for anonymous lifetimes, or if lifetimes are elided, always hrtb
* the same rule for gats
* probably `'_` should mean hrtb too
```rust
fn fun<T: Foo>(t: T)
where
T: SomeTrait<'_>, // would be nice if this meant for<'x> T: SomeTrait<'x>
// Meaning 1
fn fun<T: Foo>(t: T)
where
for<'a> T: SomeTrait<'a>, // would be nice if this meant for<'x> T: SomeTrait<'x>
// Meaning 2
fn fun<'a, T: Foo>(t: T)
where
T: SomeTrait<'a>,
// Meaning 3
fn fun<T: Foo>(t: T)
where
T: SomeTrait<impl Trait>, // Today: error
fn fun<T: Foo>(t: T)
where
for<U: Trait> T: SomeTrait<U>, // Today: error
```
Niko's argment:
* '_ and impl Trait both should "introduce name into binder" at the same depth in all "input" positions
* in output positions, they "refer back" to a name from somewhere
* `'_` refers to self lifetime
* `-> impl Trait` returns to return type of body
* in where clauses:
* you don't want to introduce a fresh name at the *item* level because it would be unconstrained
* (this is less true for lifetimes for "reasons" but definitely true for types)
* so you probably want a forall at the where clause level
* exception: value of associated types
https://github.com/rust-lang/async-fundamentals-initiative/pull/3/files
```rust=
// Later we could experiement with, e.g.:
fn fun<T: Foo>(x: T) where T::*::Output: Send {}
fn main() {
(1..3).collect::<Vec<i32>().map(<Foo as Bar>::method)
}
```
https://lang-team.rust-lang.org/design_notes/fn_type_trait_impls.html
## 2021-09-28
* https://rust-lang.github.io/async-fundamentals-initiative/evaluation.html
* MVP (niko to open a PR describing MVP on the repo):
* Straightforward desugaring
* async fn in trait desugars to an anonymous associated type that implements Future
* async fn in impl
* No dyn
* Can only use async fn in impl if you had one in the trait
* Next steps:
* [Something with dyn](https://rust-lang.github.io/async-fundamentals-initiative/evaluation/challenges/dyn_traits.html)
* [Bounding futures](https://rust-lang.github.io/async-fundamentals-initiative/evaluation/challenges/bounding_futures.html)
* Naming futures
* associated type inference
* typeof for fn types
* "some other crazy stuff"
Regarding the last bullet in "MvP":
```rust
impl Iterator for Bar {
fn next(&self) -> Option<u32> {
// ^^^ "infers" that `type Item = u32`
None
}
}
trait AsyncThing {
type Bar<'me>: Future<Output = ()> + 'me;
fn do_it(&self) -> Self::Bar<'_>;
}
impl AsyncThing for Bar {
fn do_it(&self) -> impl Future<Output = ()> {
// ^^^^^^^^^^^^^^^^^^^^^^^ Self::Bar
}
}
impl AsyncThing for Bar {
async fn do_it(&self) {
// infer that BAr = impl Future
}
}
```
## 2021-09-23
Niko would like it if traits had to be declared dyn
```rust
dyn trait Foo {
}
```
Why?
* Implementation soundness reasons
* Transparency / semver
* Don't accidentally make something not dyn safe
* It's clearer to users that something is happening
Plausible route:
* You have to supply the dyn impl
* `#[derive(dyn)]` to get the "default"
* this would be an edition change, obviously
```rust
//
trait Foo {
async fn bar(&self);
}
impl Foo for dyn Foo {
type Bar = Box<dyn Future<Output = ()>>;
fn bar(&self) -> Box<dyn Future<Output = ()>> {
vtable(self)[0](self)
}
}
// "the vtable"
impl dyn Foo for T {
fn bar(&self) {
Box::new(T::bar(self))
// ^^^^^^ the actual impl you wrote
}
}
impl Foo for T {
fn bar(&self) {
...
}
}
```
```rust
dyn trait Foo {
// Might want the Box thing here
fn bar(&self) -> impl Iterator<Item = u32>;
}
dyn trait Foo { // dyn Foo<Bar = ...>
type Bar: Debug;
fn bar(&self) -> Self::Bar;
}
dyn trait Foo {
// Might want the Box thing here
fn bar(&self, input: impl Iterator<Item = u32>) -> impl Iterator<Item = u32>;
}
```
Underlying mechanisms:
* Trait methods that return `impl Trait`:
* Only works for traits that `impl Trait for Box<dyn Trait>`
* Vtable shim that boxes and creates `Box<dyn Trait>`
* Controlling the kind of box (we have no idea how to do this yet, apart from `dyn(Box)`)
Why not return unsized values?
* Because futures have to have statically known size
Why not determine it from vtable?
```rust
let (tx, rx) = channel();
let f: impl Future<Output = u32> = async move {
let fut: dyn Future<Output = u32> = rx.receive().await;
fut.await
};
// How big is `f`?
```
```rust
let (tx, rx) = channel();
let f: impl Future<Output = u32> = async move {
let fut: dyn Future<Output = u32> = rx.receive().await.box;
// ^^^ something that lets this work
fut.await
};
// How big is `f`?
```
### Defining the underlying mechanisms
```rust
struct Obj<trait T> {
exists type E: T;
data: Box<E>,
vtable: vtable<E: T>,
}
impl<trait T> Obj<T> {
fn new<E: T>(e: E) -> Obj<T> {
let vtable = magic_get_vtable::<E>(&e);
let data = Box::new(e);
Obj { data, vtable }
}
fn *(*) from T {
... some code that extracts from vtable... somehow ...
}
}
impl as<Obj<trait T>> for T { ... allocates a box ... }
```
```rust
let x = Obj::new(some_value);
```
### What Niko wants
* dyn is always 1 word
* so dyn Trait is Sized
* `x as dyn Trait` requires that `x` is a pointer (in practice)
* `box struct Foo` means that `Foo` is actually `Box<Foo>` (covenience)
* `dyn trait Foo` declare that a trait is "dyn-able"
* `dyn Trait: Trait` works kind of universally
* `fn foo(x: dyn Trait)` -- you could pass in a `&Foo` where `Foo: Trait` (which has size one word)
* `fn foo(x: &dyn Trait)` is a pointer to pointer, not much we can do about that
## 2021-09-22
MVP
```rust
trait Foo {
async fn method(&self);
}
impl Foo for u32 {
async fn method(&self);
}
// desugars to
trait Foo {
type _Foo /* unnameable */: Future<Output = ()>;
fn method(&self) -> Self::_Foo;
}
impl Foo for u32 {
type _Foo /* unnameable */ = impl Future<Output = ()>;
fn method(&self) -> Self::_Foo {
async move { ... }
}
}
```
* dyn??
### What works
```rust
async fn my_function<T: Foo>(x: T) {
x.method().await;
}
#[async]
fn main() {
tokio::spawn(move async {
my_function(22);
});
}
impl Foo for i32 {
async fn method(&self) {
tokio::println!("Hello, world {}", self).await
}
}
```
### What doesn't
```rust
fn my_function<T: Foo>(x: T) {
tokio::spawn(move async {
// cannot write this because `T::_Foo` is not known to be Send
x.foo();
});
}
```
```rust
fn foo(x: &dyn Foo) {
// ^^^^^^^ did not provide a value for `_Foo`
}
```
### Implementation work required
* Extend the parser
* Lower the thing in HIR lowering
* Improve error messages in some cases
* Make these traits not dyn-safe for now
### Prepare a test suite
* Prepare a test suite
https://rust-lang.github.io/async-fundamentals-initiative/
https://github.com/rust-lang/async-fundamentals-initiative
https://rust-lang.github.io/async-fundamentals-initiative/evaluation/challenges/dyn_traits.html
## Dyn traits
Normal "default impl" for dyn generated by the compiler
```rust
trait Foo {
type Bar;
fn method(&self);
}
impl<B> Foo for dyn Foo<Bar = B> {
type Bar = B;
fn method(&self) {
let f: fn(&Self) = get_method_from_vtable(self)
// ^ literally the same function
f(self)
}
}
impl Foo for u32 {
fn method(self: &u32) { XXX }
}
// compiles to:
//
// Vtable_Foo = [ ..., `<u32 as Foo>::method` ]
// fn `<u32 as Foo>::method`(self: &u32) { XXX }
```
For async fn:
```rust
trait Foo {
async fn method(&self);
}
impl<B> Foo for dyn Foo {
type Bar = Box<dyn Future<Output = ()>>;
fn method(&self) -> Box<dyn Future<Output = ()>> {
}
}
// compiles to:
//
// Vtable_Foo = [ ..., `<u32 as Foo>::methodX`]
// fn `<u32 as Foo>::method`(self: &u32) { XXX }
// fn `<u32 as Foo>::methodX`(self: &u32) -> Box<dyn> { Box::new(TheFuture) }
```
### Auto traits and resulting futures
Basically we just need multiple impls:
```rust
trait Foo {
async fn method(&self);
}
impl<B> Foo for dyn Foo {
type Bar = Box<dyn Future<Output = ()>>;
fn method(&self) -> Box<dyn Future<Output = ()>> {
}
}
impl<B> Foo for dyn Foo * Send {
type Bar = Box<dyn Future<Output = ()> + Send>;
fn method(&self) -> Box<dyn Future<Output = ()>> {
}
}
// compiles to:
//
// Vtable_Foo = [ ..., `<u32 as Foo>::methodX`]
// fn `<u32 as Foo>::method`(self: &u32) { XXX }
// fn `<u32 as Foo>::methodX`(self: &u32) -> Box<dyn> { Box::new(TheFuture) }
```
### Avoiding hard-coding box
"if you give me a box, I give you a box"
but is this what we really want? Then dyn foo doesn't quite work the same
```rust
trait Foo {
async fn method(&self);
}
impl<B> Foo for Box<dyn Foo> {
type Bar = Box<dyn Future<Output = ()>>;
fn method(&self) -> Box<dyn Future<Output = ()>> {
}
}
impl<B> Foo for dyn Foo * Send {
type Bar = Box<dyn Future<Output = ()> + Send>;
fn method(&self) -> Box<dyn Future<Output = ()>> {
}
}
// compiles to:
//
// Vtable_Foo = [ ..., `<u32 as Foo>::methodX`]
// fn `<u32 as Foo>::method`(self: &u32) { XXX }
// fn `<u32 as Foo>::methodX`(self: &u32) -> Box<dyn> { Box::new(TheFuture) }
```
```rust
fn foo<T>(x: Box<T>) where T: ?Sized + Foo { ... }
```
"I tell you what I want, what I really really want"
```rust
#[async_dyn_type(SmallBox<4, _>)]
trait Foo {
}
```
```rust
trait Foo {
async fn method(&self);
}
impl<B> Foo for dyn(Box) Foo {
type Bar = Box<dyn Future<Output = ()>>;
fn method(&self) -> Box<dyn Future<Output = ()>> {
}
}
```
### Embedded workloads
* not depending on box
* inline
* smallbox
* maybe you have some allocator object?
### Opening up dyn for Foo for anyone
rust```