I'm trying to receive a async callback, I have this simple example
#![allow(unused_variables, unused_imports, dead_code)]
use futures::future::{FutureExt, LocalBoxFuture};
use async_std::prelude::*;
use async_std::fs::{read_dir, DirEntry};
use async_std::path::Path;
use tokio::prelude::*;
async fn foo(message: String, cb: &dyn Fn(String) -> dyn Future<Output=()>) {
cb(message).await;
}
#[tokio::main]
async fn main() {
}
Which obviously won't compile
src/main.rs|10 col 5 error 277| the size for values of type `dyn core::future::future::Future<Output = ()>` cannot be known at compilation time
|| |
|| 10 | cb(message).await;
|| | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|| |
|| = help: the trait `std::marker::Sized` is not implemented for `dyn core::future::future::Future<Output = ()>`
|| = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
|| = note: all local variables must have a statically known size
|| = help: unsized locals are gated as an unstable feature
|| For more information about this error, try `rustc --explain E0277`.
I can't understand how it doesn't know the size. Since is a reference it would be an address size (I'm trying my C background here), but I really can't understand this error, what I'm missing?
I put dyn in the return type because impl Future<()> was not possible there.
The generics are a got catch, so you're delaying the type resolution to "call time", nice trick, I was struggling with dyn vs impl. My understand is that impl is solved at compiled time "I'm returning something the implements trait Foo and that implementation exists and is track-able at compile time", while dyn means "Well this may vary and can only be know at compile time", thinks that depend on user input are a good example of dyn stuff...
I never though about generics, they are like removing the type responsibility from the function writer to the caller. Is this right? So if I have a function that I don't know what will return (and it can't be dyn because is unsized) I can used generics to delay the decision to the function call
Thanks again guys for taking your time to answer this
The difference with impl vs dyn is that impl is turned into a concrete type at compile time, whereas dyn stays unknown even at compile time, and dynamic dispatch is used at runtime to figure out the actual type. To be clear, dyn is not known at compile time.
Additionally it seems like you're thinking of impl in an argument as a different thing from generics, but it isn't. Using impl in an argument to the function is still using generics, it's just more hidden. On the other hand, using impl in the return value is a different thing from generics, because in that case the function author chooses the concrete type.