Skip to content

Thunk does not accept closures with multiple arguments #20110

@mzabaluev

Description

@mzabaluev

It would seem easy to create a Thunk from a multi-argument FnOnce:

#![feature(default_type_params)]

use std::thunk::Thunk;

fn do_with_callback<F>(callback: F)
        where F: FnOnce(int, int) + Send {
    let th = Thunk::with_arg(callback);
    th.invoke((2, 2));
}

fn main() {
    do_with_callback(|x, y| {
        println!("{}", x * y);
    });
}

However, the compiler produces a puzzling error:

thunk-with-multi-args.rs:7:14: 7:29 error: the trait core::ops::Fn(_) -> _ is not implemented for the type F

The issue seems to occur due to use of the unary closure type syntax where generic parameters are needed, and not using .call_once explicitly. I've managed to fix it thus:

#![feature(default_type_params)]
#![feature(unboxed_closures)]

pub struct Thunk<A=(),R=()> {
    invoke: Box<Invoke<A,R>+Send>
}

impl<R> Thunk<(),R> {
    pub fn new<F>(func: F) -> Thunk<(),R>
        where F : FnOnce<(),R> + Send
    {
        Thunk::with_arg(func)
    }
}

impl<A,R> Thunk<A,R> {
    pub fn with_arg<F>(func: F) -> Thunk<A,R>
        where F : FnOnce<A,R> + Send
    {
        Thunk {
            invoke: box func
        }
    }

    pub fn invoke(self, arg: A) -> R {
        self.invoke.invoke(arg)
    }
}

pub trait Invoke<A=(),R=()> {
    fn invoke(self: Box<Self>, arg: A) -> R;
}

impl<A,R,F> Invoke<A,R> for F
    where F : FnOnce<A,R>
{
    fn invoke(self: Box<F>, arg: A) -> R {
        let f = *self;
        f.call_once(arg)
    }
}

Note how the new constructor is now redundant. Perhaps the specialized constructor should be dropped and Thunk::with_arg should be renamed to Thunk::new.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions