Skip to content
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

Provide wrappers over Box<Fn> #20878

Closed
bombless opened this issue Jan 10, 2015 · 12 comments
Closed

Provide wrappers over Box<Fn> #20878

bombless opened this issue Jan 10, 2015 · 12 comments

Comments

@bombless
Copy link
Contributor

Something like this:

#![feature(unboxed_closures, box_syntax)]
#![allow(unstable)]
struct Proxy<'a, Args, Ret> {
    closure: Box<Fn<Args, Ret> + 'a>
}
impl<'a, Args, Ret> Fn<Args, Ret> for Proxy<'a, Args, Ret> {
    extern "rust-call" fn call(&self, args: Args)->Ret {
        self.closure.call(args)
    }
}
impl<'a, Args, Ret> Proxy<'a, Args, Ret> {
    fn new<F: Fn<Args, Ret> + 'a>(closure: F)->Proxy<'a, Args, Ret> {
        Proxy { closure: box closure }
    }
}
fn main(){
    let celebrate = Proxy::new(|&: num: i64| {
        println!("Feels great to implement C++ std::function in {} lines.", num)
    });
    let lucy_number = Proxy::new(|&: num: i64| {
        println!("My lucky number is {}", num)
    });
    let func = if std::rand::random() { celebrate } else { lucy_number };
    func(25)
}

Or is it part of the plan? :p

@reem
Copy link
Contributor

reem commented Jan 10, 2015

What's the benefit of the Proxy type over just using an Fn trait object directly?

@bombless
Copy link
Contributor Author

A proxy is the same type while arguments type and return type are the same, thus makes it possible to write a if while both arms are closures.
Other than if, match arms can benefit from it, too.

@reem
Copy link
Contributor

reem commented Jan 10, 2015

@bombless You can do the same thing by using regular trait objects, like so:

#![feature(box_syntax)]
#![allow(unstable)]
fn main(){
    let celebrate: Box<Fn(i64)> = box |&: num: i64| {
        println!("Feels great to implement C++ std::function in {} lines.", num)
    };
    let lucky_number: Box<Fn(i64)> = box |&: num: i64| {
        println!("My lucky number is {}", num)
    };
    let func = if std::rand::random() { celebrate } else { lucky_number };
    func(25)
}

You can even avoid the type annotations in a lot of cases.

@bombless
Copy link
Contributor Author

@reem For my experience, annotations cannot be avoided in most cases.
And you are right, I usually do things in your way. I just think offering standard proxy will make it easier to write such code.
BTW it seems that we will have bare trait one day and this will no longer be a problem ( being able to return a bare trait from a function ).

@Gankra
Copy link
Contributor

Gankra commented Jan 10, 2015

Seems like this bug just amounts to "closures are unergonomic", then?

@reem
Copy link
Contributor

reem commented Jan 10, 2015

"conversion to trait objects is verbose and unergonomic" probably, which I have definitely experienced.

@bombless
Copy link
Contributor Author

@gankro We can call it a feature, and I think the issue is the lack of relative facilities.

@bombless
Copy link
Contributor Author

@reem Yeah maybe things will change once type inference is improved.
Is there a chance that boxing will be able to be done automatically according to type inference? If so then things can even become better.

@bombless
Copy link
Contributor Author

#18875
If I understand correctly the Proxy code will not compile at the next nightly build of rustc, sad story.

@bombless
Copy link
Contributor Author

nikomatsakis@152d623#diff-0
My bad, it's just behind an unboxed_closures feature gate, as always.

@kmcallister kmcallister changed the title Is there a general function facility in std library already? Provide wrappers over Box<Fn> Jan 11, 2015
@sellibitze
Copy link
Contributor

It seems the proxy type thingy serves no purpose. Sometimes, a function is all you need:

#![feature(unboxed_closures, box_syntax)]
#![allow(unstable)]

fn anyfunc<'a, Args, Ret, F>(closure: F) -> Box<Fn<Args, Ret> + 'a>
where F: Fn<Args, Ret> + 'a {
    box closure
}

fn main(){
    let celebrate = anyfunc(|&: num: i64| {
        println!("Feels great to implement C++ std::function in {} lines.", num)
    });
    let lucy_number = anyfunc(|&: num: i64| {
        println!("My lucky number is {}", num)
    });
    let func = if std::rand::random() { celebrate } else { lucy_number };
    func(25)
}

It's actually similar to what you would do in C++: write a function template à la make_shared etc. But I'm not sure if this is important enough to include it into the standard library.

@alexcrichton
Copy link
Member

I agree with @reem, @gankro, and @sellibitze in that this may just be an issue of ergonomics as boxed trait objects/closures sound like they do what you already want. Could you open a new issue more focused on the ergonomics of boxed closures if you're concerned? Thanks!

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

6 participants