-1

I have three traits that are dependent on each other, but I can't find a way to define these traits statically without using dyn.

Defining two seems very simple:

pub trait TA<B: TB<Self>> {
    fn getB() -> Option<B>;
}

pub trait TB<A: TA<Self>> {
    fn getA() -> Option<A>;

}

But defining similar thing with three traits seems impossible (the code bellow doesn't compile):

pub trait TA<B: TB, C: TC> {
    fn getB() -> Option<B>;
    fn getC() -> Option<C>;
}

pub trait TB<A: TA, C: TC> {
    fn getA() -> Option<A>;
    fn getC() -> Option<C>;
}

pub trait TC<A: TA, B: TB> {
    fn getA() -> Option<A>;
    fn getB() -> Option<B>;
}
Guy Korland
  • 9,139
  • 14
  • 59
  • 106
  • This could be interpreted in a lot of ways. I suspect that at least some of those generics should be associated types, but it's impossible to say in the abstract. – trent Apr 01 '21 at 14:10
  • What do you mean by associated types? Assume this is a generic implementation of a graph/linked-list and the nodes might have three types TA/TB/TC implementation – Guy Korland Apr 01 '21 at 15:16
  • The difference between a type parameter and an associated type is that parameters are chosen by the user of the trait, but associated types are chosen by the type implementing it. [When is it appropriate to use an associated type versus a generic type?](https://stackoverflow.com/q/32059370/3650362) If it would not make sense to implement both `TC` and `TC` for the same type `Baz`, then they should probably be associated types, not parameters. [Here's what that might look like](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=062b05bf63efb1b6bfb2575bf963ff62). – trent Apr 01 '21 at 15:30
  • It's not immediately apparent to me how a graph or linked list would use these traits, so I can't be sure. But do consider reading [Learn Rust With Entirely Too Many Linked Lists](https://rust-unofficial.github.io/too-many-lists/) before trying to make any nontrivial data structures in Rust. – trent Apr 01 '21 at 15:36
  • @trentcl thanks your reference to associated types really helped! Your solution is much better. – Guy Korland Apr 02 '21 at 09:56

1 Answers1

0

It seems like with another thought it was easier than I thought.

pub trait TA<B: TB<Self, C>, C: TC<Self, B>> {
    fn getB() -> Option<B>;
    fn getC() -> Option<C>;
}

pub trait TB<A: TA<Self, C>, C: TC<Self, A>> {
    fn getA() -> Option<A>;
    fn getC() -> Option<C>;
}

pub trait TC<A: TA<A, Self>, B: TB<B, Self>> {
    fn getA() -> Option<A>;
    fn getB() -> Option<B>;
}

Edit: @trenctl solution bellow looks much cleaner

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=062b05bf63efb1b6bfb2575bf963ff62

trait Ta {
    type B: Tb<A = Self, C = Self::C>;
    type C: Tc<A = Self, B = Self::B>;
    fn get_b(&self) -> Option<Self::B>;
    fn get_c(&self) -> Option<Self::C>;
}

trait Tb {
    type A: Ta<B = Self, C = Self::C>;
    type C: Tc<B = Self, A = Self::A>;
    fn get_a(&self) -> Option<Self::A>;
    fn get_c(&self) -> Option<Self::C>;
}

trait Tc {
    type A: Ta<C = Self, B = Self::B>;
    type B: Tb<C = Self, A = Self::A>;
    fn get_a(&self) -> Option<Self::A>;
    fn get_b(&self) -> Option<Self::B>;
}
Guy Korland
  • 9,139
  • 14
  • 59
  • 106