Way to combine traits bound for reference type?

I found this (Is there a way to combine generic trait bounds?)
but I want to do like this:

fn foo<T>(x: T) -> T
where
    T: Add<T, Output = T>,
    for<'a> T: Add<&'a T, Output = T>,
    for<'a> &'a T: Add<T, Output = T>,
    for<'a> &'a T: Add<&'a T, Output = T>,
{
    &x + (&x + &x + &x) + x
}

fn bar<T>(x: T) -> T
where
    // I don't want to write twice
    T: Add<T, Output = T>,
    for<'a> T: Add<&'a T, Output = T>,
    for<'a> &'a T: Add<T, Output = T>,
    for<'a> &'a T: Add<&'a T, Output = T>,
{
    foo(x)
}

Can I name this constraint and reuse?

In theory, something along the lines of this playground should, eventually, work. Sadly, the current implementation of the compiler does not support it.

Another option to solve this in the future would be having actual support for trait aliases (the playground I linked is the current way to hack into that behavior).

This means that currently, no, there is no way to have an official shortcut for these bounds.

This only leaves us with the last resort solution to avoid code duplication: macros.

Alas, a macro cannot expand (directly) to where clauses, which means that "classic" / "simple" macros won't be enough: we'll need to "go nuclear" and use callback-based macros:

with_Add_bounds! { T, ( $($bounds:tt)* ) => (
    fn foo<T>(x: T) -> T where $($bounds)* {
        &x + (&x + &x + &x) + x
    }
    
    fn bar<T>(x: T) -> T where $($bounds)* {
        foo(x)
    }
)}

/* == Implementation == */

// `with_…` `__emit__!` is the macro version of
// Continuation-Passing Style, which allows to have macros expand
// to *anything*.
macro_rules! with_Add_bounds {(
    $T:ident, $($rules:tt)*
) => (
    macro_rules! __emit__ { $($rules)* } __emit__! {
        $T : ::core::ops::Add<$T, Output = $T>,
        for<'__any>
            $T : ::core::ops::Add<&'__any $T, Output = $T>
        ,
        for<'__any>
            &'__any $T : ::core::ops::Add<$T, Output = $T>
        ,
        for<'__any>
            &'__any $T : ::core::ops::Add<&'__any $T, Output = $T>
    }
)} use with_Add_bounds;

Thx for reply.

The first code requires

fn foo<T: FlexibleAdd>(x: T) -> T
where for<'a> &'a T: Add<T, Output = T> + Add<Output = T>, // <== this
{
    &x + (&x + &x + &x) + x
}

this, but if the RFC hits that is never needed, yes?
That's nice and the RFC itself looks very convenient.

To be honest, I completely couldn't read the second code. macro_rules in macro_rules...?
I googled and found text for lisp. I have to read that.

1 Like