[solved] [lifetimes] Can I unbox this closure? (And then box it myself)

I have a struct Statistic<A, B> which is used to fold over lots of As and then return a B.

This Statistic happens to be a bifunctor and I'd like to implement map over the first argument. (Or rather co-map)

fn map(f: Box<Fn(A1) -> A2>, s: impl Statistic<A2, B>) -> impl Statistic<A1, B>

This will store both f and s in a struct and when new data arrives (of type A1) it can apply f to get a A2 value and then feed it into s.

This works fine. But having to box all functions before passing them makes for a cumbersome API. I would prefer to box the functions myself.

fn map(f: impl Fn(A1) -> A2, s: impl Statistic<A2, B>) -> impl Statistic<A1, B>

But when I try to do this, I get a problem with lifetimes. Can you help me with that? I have been adding and removing lifetimes in mostly random places but nothing good came out of it.

Here is my working code:

// Working version
pub fn map<A1, A2, B, S>(preprocessor: Box<Fn(A1) -> A2>,
                         statistic: S)
                         -> MapStatistic<A1, A2, B, S>
    where S: Statistic<A2, B>
{
    MapStatistic::new(preprocessor, statistic)
}

// error[E0310]: the parameter type `F` may not live long enough
pub fn map<A1, A2, B, S, F>(preprocessor: F, statistic: S)
                            -> MapStatistic<A1, A2, B, S>
    where S: Statistic<A2, B>,
          F: Fn(A1) -> A2
{
    MapStatistic::new(Box::new(preprocessor), statistic)
}

Btw, most of the time is spend calculating the A values to feed into it so I'm not to worried about performance. (Between a few and a few hundred milliseconds each)

Do you need the ability for preprocessor to have references to stack variables? If not, does it work if you specify a 'static lifetime bound for F? That's likely what you're running into anyway since Box<Trait> is effectively Box<Trait + 'static>.

Also, if you're starting out with a generic F closure type, why do you need to box it? It would seem you can pass the generic type all the way through to MapStatistic and avoid boxing. Of course it's hard to say more given you've not shown the other code.

2 Likes

No, I don't need the ability to reference stack variables at all. Your solution works perfectly! Thanks a lot.

I did believe I would need to Box the closure in order to store it in a struct. If that isn't the case I can try completely unboxing it.

You can store it in the struct in its generic form so long as the struct itself takes that generic parameter, of course.

1 Like

That is nice! I'm throwing out Boxes left and right :smiley:

1 Like