Before explaining what the trick is and how it works, I'll take a general example: let's say in a Rust codebase or library you find a better way of doing something, but you still want to keep compatibility with the rest of the codebase or ecosystem. Say you have a new trait Awesome that does what Debug does, but better (for some definition of better).

You may want to express code that can consume a value that it either Awesome or Debug like this:

fn do_it(value: impl Awesome or Debug) {
    if impls!(value, Awesome) {
        // use Awesome's logic
    } else {
        // use Debug's logic
    }
}

This syntax is invented, but the idea is: if the caller gives you a type that implements Awesome use its implementation, otherwise fallback to Debug.

A concrete example of such a need is the crate maud, that declares the Render trait, which is a better Display because it handles html-escaping more efficiently. A simplifier version of it is:

trait Render {
    /// Append the data to the buffer,
    /// escaping it as necessary
    fn render_to(&self, buffer: &mut String);
}

The trick

To illustrate, say this is your Awesome trait and that you've implemented it for a list of integers:

trait Awesome {
    fn make_it_awesome(&self) -> String;
}

impl Awesome for Vec<i32> {
    fn make_it_awesome(&self) -> String {
        "AWESOME".to_string()
    }
}

Then you prepare the incantation with:

struct Choose<T>(T);

trait UseDebug {
    fn choose<T: Debug>(&self, value: &T) -> String {
        format!("{:?}", value)
    }
}

trait UseAwesome {
    fn choose<T: Awesome>(&self, value: &T) -> String {
        value.make_it_awesome()
    }
}

impl<T: Debug> UseDebug for Choose<&T> {}

impl<T: Awesome> UseAwesome for &Choose<&T> {}

Then you can use it like this:

fn main() {
    // Uses the `Awesome` implementation
    let x = vec![3, 14, 15];
    assert_eq!((&&Choose(&x)).choose(&x), "AWESOME");

    // Uses the `Debug` implementation
    let x = 31415;
    assert_eq!((&&Choose(&x)).choose(&x), "31415");
}

Unfortunately, I don't think that you can write a function like fn do_it() in the opening of this blog post, instead you can declare it as a macro:

macro_rules! do_it {
    ($value:expr) => {{
        let ref_to_value = &$value;
        (&&Choose(ref_to_value)).choose(ref_to_value)
    }}
}

fn main() {
    assert_eq!(do_it!(31415), "31415");
    assert_eq!(do_it!(vec![3, 14, 15]), "AWESOME");
}

Here's a link to Rust's language playground if you want to tweak and play with it yourself!

How and why it works

The trick exploits how Rust looks for the implementation of the method when you write something like a.b(). You can check the language's reference for the details, but in short: if the type of the receiver a is T, Rust will:

  1. first look for a candidate implemented for T, &T or &mut T. Return it if found.
  2. if possible, dereference a with Deref::deref(&a) into T2 = <T as Deref>::Target then look for a candidate implemented for T2, &T2 or &mut T2. Return it if found.
  3. repeat 2 until a candidate is found or the expression can no longer be dereferenced

This may seem quite convoluted and arbitrary, but it's central to how Rust works. For example, there is no method len() in String. Instead, it's declared in str. When you write a.len() and a is a String, Rust will first search len() in String, &String and &mut String. Since it doesn't exist, it will then deref String to str and repeat the search, finding it in &str.

So you probably already see where I'm going with all of this: the trick is to use these rules and the helper struct Choose<T> to first try to match Awesome and, only in after a dereference step, Debug.

When I wrote (&&Choose(&x)).choose(&x), the receiver is now &&Choose(&x). That's a lot of borrows, for sure, but look carefully: the type of this expression is &&Choose<&T>, where T is the type of the value x. Rust will look for the implementation of the method choose() in it.

Let's assume that T implements both Awesome and Debug. So the declaration impl<T: Debug> UseDebug for Choose<&T> {} means that UseDebug is available for Choose<&T>, which means that UseDebug::choose() is available for &Choose<&T>. This extra & comes from the fact that choose() takes &self.

Likewise, the declaration impl<T: Awesome> UseAwesome for &Choose<&T> {} means that UseAwesome::choose() is available for &&Choose<&T>. Note one extra & when compared with UseDebug, that's the heart of this trick!

Think like the compiler: Rust will consider &&Choose<&T>: UseAwesome::choose() is a candidate, however UseDebug::choose() is not because it's declared for &Choose<&T> (one less &). So the single candidate is chosen and the code compiled is x.make_it_awesome().

On the other hand, if T does not implement Awesome, then UseAwesome::choose() is no longer a candidate for &&Choose<&T>. Due to the lack of candidates, Rust dereferences &&Choose<&T> into &Choose<&T> and find the only candidate now UseDebug::choose(). The compile code then is format!("{:?}", x).

Other possible (semi-)solutions

I'll show some possible attempts and semi-solutions to the problem, that I can think of:

Use blanket implementations

You can implement your trait Awesome to every type that implements Debug with something like:

impl<T> Awesome for T
where
    T: Debug
{
    // ...
}

This works, but you cannot manually implement Awesome to types that have Debug. If great part of the reason to have created Awesome is to provide something better than Debug (performance and/or correctness), then it's sad.

Use an adaptor wrapper

struct MakeItAwesome<T>(pub T);

impl<T> Awesome for MakeItAwesome<T>
where
    T: Debug
{
    // ...
}

fn do_it(value: impl Awesome) {
    // ...
}

This forces the caller to pass you either something that implements Awesome directly, or wrap it on a helper struct MakeItAwesome. This can range from verbose to impossible, if the calling code is itself generic.

Use an enum

enum DebugOrAwesome<D = (), A = ()> {
    Debug(D),
    Awesome(A)
}

fn do_it<D, A>(value: DebugOrAwesome<D, A>) where
    D: Debug,
    A: Awesome
{
    match value {
        DebugOrAwesome::Debug(value) => { /* ... */ }
        DebugOrAwesome::Awesome(value) => { /* ... */ }
    }
}

But this requires the caller to choose the right variant and provide a "dumb" type for the other variants.