Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it intentional that cmp::Eq is implemented for fn(&'a T) -> T but not fn(&T) -> T?

Tags:

rust

Take the following valid snippet in Rust 1.25.0:

use std::marker::PhantomData;

trait Foo {
    type Eq: Eq;
}

struct Bar<'a>(PhantomData<&'a u8>);

impl<'a> Foo for Bar<'a> {
    type Eq = fn(&'a u32) -> u32;
}

As seen on the playground, this shows that Eq is implemented for fn(&'a T) -> T.

If we make a very small change, removing the lifetime of the associated type:

use std::marker::PhantomData;

trait Foo {
    type Eq: Eq;
}

struct Bar<'a>(PhantomData<&'a u8>);

impl<'a> Foo for Bar<'a> {
    type Eq = fn(&u32) -> u32;
}

We can see that Eq is not implemented for fn(&u32) -> u32:

error[E0277]: the trait bound `for<'r> fn(&'r u32) -> u32: std::cmp::Eq` is not satisfied
 --> src/main.rs:9:10
  |
9 | impl<'a> Foo for Bar<'a> {
  |          ^^^ the trait `std::cmp::Eq` is not implemented for `for<'r> fn(&'r u32) -> u32`
  |
  = help: the following implementations were found:
            <extern "C" fn(A) -> Ret as std::cmp::Eq>
            <unsafe fn(A) -> Ret as std::cmp::Eq>
            <extern "C" fn(A, ...) -> Ret as std::cmp::Eq>
            <unsafe extern "C" fn(A, ...) -> Ret as std::cmp::Eq>
          and 2 others

Is this intentional, an oversight and should be implemented, or a bug? If it's the first, what are the reasons for not doing it?

Looking at the source code for fn, we see that they implement PartialEq using raw pointer equivalence, i.e. if the address is the same, it must be the same function. Why would this not hold for fn(&T) -> T?

One option that has been presented to me is that fn(&T) -> T is generic over the lifetime of the argument and cannot therefore be logically Eq. fn(&'a T) -> T is not generic, as the lifetime has been specified to be 'a. I'm not quite sure I accept/understand this hypothesis so if anyone has a good argument for it I would accept that too.

like image 593
Emoun Avatar asked Mar 29 '18 23:03

Emoun


People also ask

What is Partialeq in Rust?

Trait for equality comparisons which are partial equivalence relations. This trait allows for partial equality, for types that do not have a full equivalence relation. For example, in floating point numbers NaN !=


1 Answers

Probably because when you compare two fn(&T) -> T, you're really comparing an fn(&'a T) -> T with an fn(&'b T) -> T with no way to check that the lifetimes 'a and 'b are the same, whereas when you compare two fn(&'a T) -> T, you know that the lifetimes are the same.

Note: this is only a supposition on my part, I have no authoritative information on the matter.

like image 96
Jmb Avatar answered Sep 23 '22 08:09

Jmb