Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does trait implementation for Box<T> conflict with Fn()?

A simplistic program to demonstrate this behavior:

use std::boxed::Box;

struct Cow;

trait CanSpeak {
    fn speak(&self);
}

impl CanSpeak for Cow {
    fn speak(&self) {
        println!("moo");
    }
}

impl<F: Fn()> CanSpeak for F {
    fn speak(&self) {
        self();
    }
}

impl<T: CanSpeak> CanSpeak for Box<T> {
    fn speak(&self) {
        (**self).speak()
    }
}

fn lol_speak() {
    println!("lol")
}

fn lets_speak<T: CanSpeak>(t: & T) {
    t.speak();
}

fn main() {
    let cow = Cow;
    lets_speak( &cow );

    lets_speak( &lol_speak );

    let boxed_cow = Box::new(Cow);
    lets_speak( &boxed_cow );
}

Compilation fails with:

test.rs:15:1: 19:2 error: conflicting implementations for trait `CanSpeak` [E0119]
test.rs:15 impl<F: Fn()> CanSpeak for F {
test.rs:16     fn speak(&self) {
test.rs:17         self();
test.rs:18     }
test.rs:19 }
test.rs:15:1: 19:2 help: run `rustc --explain E0119` to see a detailed explanation
test.rs:21:1: 25:2 note: note conflicting implementation here
test.rs:21 impl<T: CanSpeak> CanSpeak for Box<T> {
test.rs:22     fn speak(&self) {
test.rs:23         (**self).speak()
test.rs:24     }
test.rs:25 }
error: aborting due to previous error

My questions are:

  1. As far as I can tell Box<T> does not implement Fn() trait. Then why does above example fail?
  2. What is the correct implementation for what I'm trying to do?

I've just started learning Rust. Thanks for your help.

like image 357
Vikas Avatar asked Oct 17 '15 02:10

Vikas


1 Answers

The two do conflict, because it is possible for a type Box<T> to have T implementing CanSpeak and Box<T> implementing Fn(). Rust coherence rules aren’t about what is but what can be.

Here’s an example of implementing Fn() for Box<Cow>, which would clearly explode things if it allowed your two generic trait implementations:

// (This attribute on the crate.)
#![feature(unboxed_closures, core)]

impl Fn<()> for Box<Cow> {
    extern "rust-call" fn call(&self, _: ()) { }
}

impl FnMut<()> for Box<Cow> {
    extern "rust-call" fn call_mut(&mut self, _: ()) { }
}

impl FnOnce<()> for Box<Cow> {
    type Output = ();
    extern "rust-call" fn call_once(self, _: ()) { }
}
like image 131
Chris Morgan Avatar answered Nov 12 '22 13:11

Chris Morgan