Specialization of trait implementation at multiple levels

I am trying to provide a broad implementation for FnOnce, followed by a more specific implementation for FnMut, in turn followed by an even more specific implementation for Fn. I am able to successfully compile the program if I keep any two implementations, with the broadest implementation (for FnOnce) marked as default, but the compiler refuses to let me have all three implementations. Here is the code:

#![feature(unboxed_closures)] // to switch from parenthetical notation to generics for `Fn*` traits
#![feature(fn_traits)] // to use `call_once` and `call` methods on Fn* traits
#![feature(specialization)] // for specialization of trait implementations
#![allow(incomplete_features)]

use std::marker::PhantomData;

pub struct Callable<
    A, // arguments as a tuple
    R, // return type
    F, // Fn trait (like Fn, FnOnce, and FnMut)
> where
    F: FnOnce<A, Output = R>,
{
    phantom_data: PhantomData<(A, R, F)>,
}

trait Runnable{
    fn run();
}

// Implementation 1: The broadest one
impl<A, R, F> Runnable for Callable<A, R, F>
where
    F: FnOnce<A, Output = R>,
{
    default fn run() {
        println!("Inside the run method for FnOnce!");
    }
}

// Implementation 2: Narrower
impl<A, R, F> Runnable for Callable<A, R, F>
where
    F: FnMut<A, Output = R>,
{
    fn run() {
        println!("Inside the run method for FnMut!");
    }
}

//Implementation 3: The most specific
impl<A, R, F> Runnable for Callable<A, R, F>
where
    F: Fn<A, Output = R>,
{
    fn run() {
        println!("Inside the run method for Fn!");
    }
}

fn main() {
    println!("Program compiled. No errors!");
}

Here is the Rust Playground link: Rust Playground

How can I accomplish all the three implementations?

This seems to work if you add default to the FnMut impl. Playground.

1 Like

Strange why we even need a second default. If the compiler can already tell which of the two defaults is broader, then why does default even need to be used?

It helps a reader understand the code. An impl without the default keyword is always used for types it applies to, while one with default may be overridden. For some more details, see RFC 1210.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.