Specialization for zero-sized functions


#1

I have the following trait

trait Foo<F> 
  where F: FnMut(&Self, &Self) -> Ordering
{
   fn  foo(&mut self, compare: F) -> bool;
}

and a blanket impl:

impl<I,F> Foo<F> for I
  where F: FnMut(&Self, &Self) -> Ordering {
    fn  foo(&mut self, compare: F) -> bool { true }
}

(playground)

I want to specialize this blanket impl so that for the type u32 when foo is called with <u32 as Ord>::cmp it returns false and otherwise true.

How can that be done?

impl<???> Foo<???> for u32 {
    fn  foo(&mut self, compare: ???) -> bool {
         if compare == <u32 as Ord>::cmp { false } else { true }
   }
}

Motivation: I want to provide explicitly-vectorized implementations of Iterator::is_sorted_by for some of the primitive types and for when the comparison operator is used in the primitive types.

In C++ this is trivial (one would just match on std::less and be done with it) but I can’t figure out how to match on <u32 as Ord>::cmp in Rust while specializing.


#2

In stable rust you can’t since the blanket has covered the case already.
There is specialization but been a long time since I last looked and no idea if on course or not for stabilization.


#3

Thanks @jonh! Yes, I am interesting in knowing how to do this with the specialization nightly feature. The places where I need this (inside std components) are allowed to use specialization on stable Rust, so that’s not really a concern :slight_smile:


#4

I think in Rust’s specialization you’d need to define the trait impls such that trait and method selection will pick the specialized cmp version, rather than attempting to match on the fn inside the function. I don’t, however, know offhand how you’d express this one. It seems like you’d want where clause equality ... where F: <Self as Ord>::cmp but this isn’t supported AFAIK.

@withoutboats would know for sure I think.


#5

I got it to work: https://play.rust-lang.org/?gist=e62905d912ad5af7b0f4dd0a2d324cce&version=nightly

The nicer alternative would be if std would expose types that one can specialize on, like for example a struct Less(); and struct PartialGreater(); types that implement the fn_traits to map to x.cmp(y) and x.partial_cmp(y).reverse(), respectively. That way one could just specialize on these types, without having to do run-time pointer checks, which is hacky at best, and won’t work if one passes closures, etc.


#6

Yeah, I’d like to see if there’s a way (now or planned for the near future) where method selection can be used to dispatch to the appropriate function rather than ptr comparison inside a single function. The ptr comparison should get optimized out if the fn is inlined but it doesn’t look like an elegant solution.