Best way to "override" an implementation of a trait for a generic type parameter

Hello, thanks for taking a look! Don't worry, I'm not trying to violate the orphan rule :wink:

Let's say I have a trait A with some implementation for a generic type T that implements B. I would like to "override" this "default" implementation for a specific type Special that also implements B.

Currently I am archiving this by introducing an empty marker trait UsesDefaultImplementation and adding an additional trait bound on T: B + UsesDefaultImplementation in my "default" implementation and just implementing the marker trait for every type except for Special (see below). However as

I am aware that UsesDefaultImplementation is a very good candidate for an auto trait, but I am afraid of auto traits never hitting the stable channel.

I was wondering if anybody knows some better syntax I could make use of. Ideally I was hoping for something like this:

trait A {..}
trait B {..}

impl<T> A for T where T: B {
  ...
}


impl A for Special {
    //conflicting implementation with the one above,
    // since Special also implements B 
}

but unfortunately it raises an conflicting implementation error.

Current solution:

trait A {..}
trait B {..}

trait UsesDefaultImplementation;

impl<T> A for T where T: B  + UsesDefaultImplementation {
  ...
}


impl A for Special {

}

// **This** is the cumbersome part I was hoping to avoid:
impl UsesDefaultImplementation for SomeTypeThatImplementsB {}
impl UsesDefaultImplementation for AnotherTypeThatImplementsB {}
// ... many more impl statements

Shorter nightly channel solution:

#![feature(negative_impls)]
#![feature(auto_traits)]
trait A {..}
trait B {..}

auto trait UsesDefaultImplementation {}

impl !UsesDefaultImplementation for Special {}

impl<T> A for T where T: B  + UsesDefaultImplementation {
  ...
}


impl A for Special {

}

Is there another solution that I am not aware of that might be of interest?
Thanks for helping!

Given that you basically want specialization (still with soundness holes—not going to be stabilized any time soon), here we go:

#![feature(specialization)]

trait A {}
trait B {}

struct Special;

default impl<T> A for T where T: B {}

impl A for Special {}

Playground.

1 Like

Will take a look, thank you!!

(Don't actually use #![feature(specialization)] in production. It's incomplete and broken.)

2 Likes

Thank you for the Info! That's unfortunate.

Is trait B under your control? If so, maybe it's possible to extend it such that the specialty becomes part of the trait.

E.g. you could add methods with default implementations to B, and specialize those for that specific type. Hard to say more without knowing any details, though.

1 Like

Unfortunately, trait B does not happen to be controlled by me. But it is an interesting idea, thank you!

**Edit: removed the code idea regarding the original motivation behind my question, since it made no sense

I think I'd use a wrapper type around UnsafeCell and implement Debug the way I want to for that.

1 Like

The UnsafeCells are part of structs that refer to each other via the UnsafeCells in a graph like datastructure. While being a zero-cost abstraction wrapping all of the struct fields during their creation would be a lot of work in my case I'm afraid :')

Hmm, maybe it's not as much work as I originally anticipated before, will think about it, thanks!

Maybe you can wrap them only in the struct's own implementation of Debug, rather than keeping them wrapped at all times?

Note that CopyOfDebugTraitToOverrideImplementations::fmt should be unsafe if you implement it like that, as it may not be safe to access the contents of an arbitrary UnsafeCell at an arbitrary time.

1 Like

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.