Specialization on clone. What's the risk?

Hi,

The following issue is solved when I enable the specialization gated attribute:

impl<T> MyTrait for Vec<T>
where
        T: Copy + Sized + Send + Sync + ... <- other non relevant traits for the question
{}

But with min_specialization it fails, stating that

error: cannot specialize on trait `std::clone::Clone`
error: cannot specialize on trait `std::marker::Send`
error: cannot specialize on trait `std::marker::Sync`

So, now, using nightly, what are the real risks for my code to keep using the specialization attr?
I tried with many variants and they all work as expected with the full specialization attribute.

I tried with trait specialization attributes to reduce the cope of specialization, but apparently it didn't make it.

with

#![feature(min_specialization)]
#![feature(rustc_attrs)]

in my lib.rs

and

#[rustc_specialization_trait] 
impl<T> MyTrait for Vec<T>
where
        T: Copy + Sized + Send + Sync + ... <- other non relevant traits for the question
{}

the issue remains.

Thanks!

One real risk is the fact that not only is specialization unstable in the truest sense of the word (and a bit half-baked at best ATM) personally I wouldn't be surprised if the feature was removed altogether despite how useful it could be. The reason for that is that in the last couple of years, nobody has been able to figure out how to actually complete the feature, with special emphasis on lifetime specialization.

So it's fine and dandy for a toy project, but if it's supposed to do anything actually useful, it's basically begging for problems.

Also, the actual trait doesn't matter - it's all or nothing with specialization as I understand it, and there most likely won't be any special casing.

1 Like

You did need to add #[rustc_specialization_trait] to Clone, Send and Sync for rustc to accept that code. Note that adding #[rustc_specialization_trait] to a trait is an promise (the same way that an unsafe block is a promise) that you will not implement the trait for any type unless the implementation covers all possible lifetimes. Empirically there are implementations that violate these requirements in the ecosystem and as they are not unsafe even if there weren't yet someone could add one and as such the standard library can't mark these traits as #[rustc_specialization_trait] without enabling UB in any crate that specializes on those traits.

1 Like

So I have to find a different way, I can't add those trait on Clone and al, that would modify the std (did I get what you said right ?)

If I don't control the input type T (could be anything), there is nothing I can do, right ?

Yeah.. not realistic to keep going that route.
Thanks a lot!

Sorry to bump guys,
But there is nothing sane I can do here ?
I need to select the function depending on the trait Copy + Sized + Send

impl<T> MyTrait for Vec<T>
where
        T: Copy + Sized + Send + Sync + Other // Mainly POD or simple elements
{
        fn myfn(){}
}

impl<T> MyTrait for Vec<T>
where
        T: Other
{
        default  fn myfn(){}
}

This is a code that will be used in production so I can't rely on something that will suddenly blow on my face.

I don't see how I could work around this one.

There's no way at the moment to make the selection between the two implementations automatically. You could write a newtype wrapper that lets downstream users opt-in to the fast path if their usage allows it:

pub struct FastPathOptIn<T>(pub T);
impl<T> Deref for FastPathOptIn<T> {
    type Target=T;
    fn deref(&self)->&T { &self.0 }
}

impl<T> DerefMut for FastPathOptIn<T> {
    fn deref_mut(&mut self)->&mut T { &mut self.0 }
}

impl<T:Copy+Sized+Sync+Send+Other> MyTrait for FastPathOptIn<Vec<T>> {
    fn myfn() {
        // Fast implementation using the extra capabilities
    }
}

impl<T> MyTrait for Vec<T> {
    fn myfn() {
        // Universally-applicable implementation
    }
}
1 Like

Ok I will refactor my code around that.

Thanks a lot!