Can I achieve this without `unboxed_closure`?

I am not good at English. Sorry if there are any funny expressions.


Hi all.

I want to remove unboxed_closure (unstable feature) from following code.
(However, I want to keep generality of callback functions as much as possible.)
(Hard part for me is handling lifetimes around iter_from_vec.)

#![feature(unboxed_closures)]

fn main() {
    use std::slice::Iter;
    let vec = vec![1, 2, 3];
    let iter = callback::<_, _, Iter<i32>>(&vec, iter_from_vec);
    assert!(iter.eq(vec.iter()))
}

fn iter_from_vec(x: &Vec<i32>) -> impl Iterator<Item = &i32> + '_ {
    x.iter()
}

fn callback<F, I, O>(input: &I, f: F) -> <F as FnOnce<(&I,)>>::Output
where
    F: for<'a> Fn<(&'a I,)>
{
    f(&input)
}

Aside

About why I thought it could be done without unboxed_closure.

I previously wrote the following code with errors.

fn main() {
    let input = &42;
    let result = callback(input, identity); // đŸ’Ĩ error!
    assert_eq!(result, input);
}

fn identity(x: &i32) -> &i32 {
    x
}

fn callback<F, I, O>(input: &I, f: F) -> O
where
    F: for<'a> Fn(&'a I) -> O
{
    f(input)
}

This error was repaired with unboxed_closure.

#![feature(unboxed_closures)]

fn main() {
    let input = &42;
    let result = callback(input, identity);
    assert_eq!(result, input);
}

fn identity(x: &i32) -> &i32 {
    x
}

fn callback<F, I>(input: &I, f: F) -> <F as FnOnce<(&I,)>>::Output
where
    F: for<'a> Fn<(&'a I,)>
{
    f(input)
}

This error was repaired without unboxed_closure too (But complex...).

fn main() {
    let input = &42;
    let result = callback(input, identity);
    assert_eq!(result, input);
}

fn identity(x: &i32) -> &i32 {
    x
}

fn callback<F, I>(input: &I, f: F) -> <F as FnHelper<&I>>::Output
where
    F: for<'a> FnHelper<&'a I>
{
    f(input)
}

trait FnHelper<I>: Fn(I) -> <Self as FnHelper<I>>::Output {
    type Output;
}

impl<F, I, O> FnHelper<I> for F
where
    F: Fn(I) -> O,
{
    type Output = F::Output;
}

So I am wondering if there is a similar approach in this time.

Your FnHelper is currently the only stable way to do this.

1 Like

If you only need to call the function on the input which was also provided by the caller:

// The only thing you pass to `f` was provided by the caller
//                vvvvvvvvv
fn callback<F, I>(input: &I, f: F) -> <F as FnHelper<&I>>::Output
where
    F: for<'a> FnHelper<&'a I>

Then you can use the stable Fn trait:[1]

fn callback<'input, F, I, O>(input: &'input I, f: F) -> O
where
    F: Fn(&'input I) -> O,

However, if you need to pass in local borrows, this will not work.

// ERROR: trying to borrow a local for a caller-provided lifetime
fn callback_local<'input, F, I, O>(input: I, f: F) -> O
where
    F: Fn(&'input I) -> O,
    I: 'input,
{
    f(&input)
}

For that case I agree that you need FnHelper on stable.


  1. Here's a version that does not require a reference specifically. ↩ī¸Ž

1 Like

Thanks for your replys.

First, about the unboxed_closure alternative.
Oh, I see, there is no other way than FnHelper.
I understood. Thank you so much.

NOTE: I tried to combine iter_from_vec and FnHelper methods and failed...
I have tried various ways, but all of them result in a compile error.

However, approach with input: &'input I shown by @quinedot may be sufficient for my use case.
Thanks. I'm off to wrestle with my code again.