Skip to content

Provide wrappers over Box<Fn> #20878

New issue

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

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

Already on GitHub? # to your account

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!

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants