Skip to content

Unify closure and block #2824

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
CGQAQ opened this issue Nov 28, 2019 · 8 comments
Closed

Unify closure and block #2824

CGQAQ opened this issue Nov 28, 2019 · 8 comments

Comments

@CGQAQ
Copy link

CGQAQ commented Nov 28, 2019

Motivation: make Rust more explicit , consistent and sovle this issue

The idea is basically like every block could written as closure so can specify return type and parameters(will explain in detail later)

Async block return type infer issue

async fn a() -> Result<(), reqwest::Error> {Ok(())}
async fn b() -> Result<(), std::io::Error> {Ok(())}
fn c() {
    async {
        a().await?;
        b().await?;
        Ok(())
    };
}

This will raise compilation error:

error[E0282]: type annotations needed --> src/x.rs:6:9
  |
6 |         a().await?;
  |         ^^^^^^^^^^ cannot infer type

error: aborting due to previous error

For more information about this error, try `rustc --explain E0282`.
error: could not compile `v2yay`.

with my proposal, will become like this:

fn c() {
    async || -> Result<(), impl std::error::Error> {
        a().await?;
        b().await?;
        Ok(())
    };
}

Now you would think, what's the point about ||, it's the second use case about my proposal: make Rust a more expilict language.

In rust, almost every block could return a value, and could use some variables outset of itself

let a: Vec<u32> = Vec::new();
let _ = if true {
    a
} else {
    Vec::new()
}
println!("{:?}", a);
33 |     println!("{:?}", a);
   |                      ^ value borrowed here after move

With my proposal, every block is just same as closure, you can do this if you want instead of change a to &a everywhere:

let _ = if true |&a| -> .... {
    //                  ^ specify return type explicitly
    //            ^ specify borrow explicitly, others will move by default, all variables between || , just a new temp variable that shadows original
    //     maybe add some feature so that borrow by default, specify move explicity, that will be more convenient
} else { ... }

Of cause all is optional, just specify if you need

// same thing with while, loop ...
while true ||->xxx{}
loop ||->{}
@RustyYato
Copy link

I'm pretty sure that

async || -> ...

Is going to mean async closures. Also, with generalized type ascription, we can insert type hints anywhere.

@CGQAQ
Copy link
Author

CGQAQ commented Nov 28, 2019

I'm pretty sure that

async || -> ...

Is going to mean async closures. Also, with generalized type ascription, we can insert type hints anywhere.

That's what I mean by Title, unify closure and block, in my opinion: block just closures without arguments, but it could also use "arguments" outside of it's scope which could treat as arguments as well. So just unify these two types, make block a special closure.
This proposal is indeed backward compatible

@kennytm
Copy link
Member

kennytm commented Nov 28, 2019

Unifying the the two would break

let a = async { 1 };
let b = async || { 1 };

The type of a is impl Future<Output = i32>, while the type of b is fn() -> impl Future<Output = i32>.

@CGQAQ
Copy link
Author

CGQAQ commented Nov 28, 2019

Unifying the the two would break

let a = async { 1 };
let b = async || { 1 };

The type of a is impl Future<Output = i32>, while the type of b is fn() -> impl Future<Output = i32>.

Just a closure instant called, didn't break at all

@Ixrec
Copy link
Contributor

Ixrec commented Nov 28, 2019

Also, Rust already has control flow like return, break, continue and ? whose behavior depends on what function/closure they're in. A block and an immediately-invoked closure must be genuinely different constructs for that reason alone. async isn't introducing anything new in that regard.

@kennytm
Copy link
Member

kennytm commented Nov 28, 2019

@CGQAQ so what happens with

    let b = async || { 1 };
    b().await;
    b().await;

under this proposal

@CGQAQ
Copy link
Author

CGQAQ commented Nov 28, 2019

@CGQAQ so what happens with

    let b = async || { 1 };
    b().await;
    b().await;

under this proposal

When you . await a closure, compiler will try to convert it to a block

  1. Closure have arguments, complier will look for variables match closure arguments, if compiler found all compile success, otherwise
    compilation error,
  2. Closure don't have arguments, just convert it, done

@CGQAQ
Copy link
Author

CGQAQ commented Nov 28, 2019

Forget it, won't work

@CGQAQ CGQAQ closed this as completed Nov 28, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants