Issue working around coherence rules


#1

So I’m wanting to write something that is roughly the following (the real code would require a lot of <T as Trait>):

impl<T, Rhs> std::ops::Add<Rhs> for T where
    T: Expression,
    T::SqlType: types::marker::Addable,
    Rhs: AsExpression<T::SqlType::Rhs>,
{
    type Output = expression::ops::Add<T, Rhs::Expression>;
    
    fn add(self, rhs: Rhs) -> Self::Output {
        expression::ops::Add::new(self, rhs.as_expression())
    }
}

However, I cannot write a blanket impl for traits I do not control. I’ve been working around this issue by having a macro that gets invoked for individual concrete types. The only types that I expect to work with here that I don’t specifically control are created en-masse by a macro (these represent the columns on a database table).

The issue is, in the macro, I basically need to invoke this for all columns, regardless of whether their type implements types::marker::Addable, and I cannot reference a concrete type in a where clause. To make it more clear, the macro would expand to something like this:

impl<Rhs> std::ops::Add<Rhs> for schema::users::is_admin where
    types::Bool: types::marker::Addable,
    Rhs: AsExpression<types::Bool::Rhs>,
{
  // ...
}

This would fail because I can only reference type parameters in the where clause, not concrete types.

If I avoid doing that, it will of course fail because types::Bool does not implement types::marker::Addable. So unless I have some way to basically do an if statement in a macro, I either need some tomfoolery to work around this, or basically push the burden of specifying this onto my users.

Ultimately I intend for the macro invocation which creates the column types to get generated by a toml file anyway, so I suppose I can handle this there, but I’m interested if there’s any decent way to work around this short of a compiler plugin or codegen.

The actual commit for the actual code where I’m having this problem can be found here, if you’re looking for more context.


#2

For what little it’s worth, I’ve solved similar problems in the past by specifying all the traits I want implemented explicitly. Not pretty, but there you go.

It would be nice if Rust allowed… let’s say “non-idiomatic” and/or superfluous constructs if they’re being generated by a macro or build script. So, keep redundant where clauses illegal unless you tag them with, say, #[generated(treat_me_gentle)].

As a D-fugee, I’d be excited for Rust to get static if, but I suspect that may be a long way of, if it ever comes at all.