Generics and union of type bounds

Hello, folks.
I'm new to Rust and trying to wrap my head around generics and traits interaction. As I understand, I can limit the type my generic is defined for by using type bounds. Like this:

fn dummy<T: A+B>(arg1: T) {}

where A and B some traits. Is it correctly to think about traits A and B as kind of sets of types and about A+B as of set intersection? If so, what's about set union?

Is it possible to define a function over a union (of disjoint) traits, something like this?

trait A {
    fn method_a(self: &Self) -> String;
}

trait C {
   fn method_c(self: &Self) -> String;
}

fn func_b<T: A>(x: T) {
    println!("func_b for A: {}", x.method_a())
}

fn func_b<T: C>(x: T) {
    println!("func_b for C: {}", x.method_c())
}

Yes, that's a good way to think about it. I believe the code implementing the type system might even treat it that way.

No, it's not possible to do that in Rust. There should only be one instance of a particular "item" (i.e. struct, function, constant, etc.) with a particular name in a particular module, so it's not possible to define multiple func_b() functions.

To explain why, think about what would happen if I had some type which implements both A and C... There would be no way to know which version of func_b() to call, and because downstream users can implement any trait they want on their types, you would have no way to prevent those situations.

2 Likes

Yeah, I saw this code is being rejected by a compiler. I just don't understand whether it is for the fundamental reason or just for the sake of simplicity. My initial thought was that allowing this code should not be a problem, because afaik generic function is being specialized for a particular type and the compiler can check whether traits intersect for the type in question or not. But maybe it's doomed to become too confusing for users...

This would be some form of negative bounds with coherence and non-overlapping generic trait implementations.

trait AXorC {
    func_b(self);
}

impl<T: A + !C> AXorB for T { ... }
impl<T: C + !A> AXorB for T { ... }

(For T to meet T: !A, they must have an explicit impl !A for T {}.)

Feasible, but I doubt we're anywhere close. It also allows for some type of specialization, so it probably has to be restricted to be sound too.

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.