2021-02-25

Alternative to equality constraints for associated types

I'm trying to write this in Rust:

trait Foo {
    type T: PartialEq;

    fn get_t(&self) -> Self::T;
}

struct Bar<F1: Foo, F2: Foo> {
    f1: F1,
    f2: F2,
}

impl<F1: Foo, F2: Foo> Bar<F1, F2> {
    
    fn test_eq(&self) -> bool {
        self.f1.get_t() == self.f2.get_t()
    }
}

It refuses to compile, because F1::T might be different from F2::T, rendering the equality meaningless. I'd like to be able to resolve that by writing this:

impl<F1: Foo, F2: Foo> Bar<F1, F2>
where
    F1::T = F2::T
{
    
    fn test_eq(&self) -> bool {
        self.f1.get_t() == self.f2.get_t()
    }
}

But that tells me that equality constraints are not yet supported and refers me to this issue. Since it's been open since late 2014, I suspect it's not a feature that's arriving any time soon.

I can do this, and it'll compile:

struct Bar<T: PartialEq, F1: Foo<T=T>, F2: Foo<T=T>> {
    f1: F1,
    f2: F2,
}

impl<T: PartialEq, F1: Foo<T=T>, F2: Foo<T=T>> Bar<T, F1, F2>
{
    
    fn test_eq(&self) -> bool {
        self.f1.get_t() == self.f2.get_t()
    }
}

But then I'm adding an additional generic parameter to the struct Bar. If Foo has multiple associated types that I want to constrain in this manner, then it'll get a bit messy. My question is:

  1. Is this really the only way I can enforce this constraint, by making Bar 'more generic' with the addition of the additional type parameter T?
  2. Is this the most idiomatic way of solving this?

Edit:

I realize I simplified my example too much. Suppose I actually have a Bar that has an associated Baz that has an associated Foo that has an associated T. That's bit of a mouthful, so here is the example:

trait Foo {
    type T: PartialEq;

    fn get_t(&self) -> Self::T;
}

trait Baz {
    type F: Foo;

    fn get_inner_t(&self) -> <Self::F as Foo>::T;
}

struct Bar<B1: Baz, B2: Baz> {
    b1: B1,
    b2: B2,
}

impl<B1: Baz, B2: Baz> Bar<B1, B2>
{
    
    fn test_eq(&self) -> bool {
        self.b1.get_inner_t() == self.b2.get_inner_t()
    }
}

Of course it still doesn't compile because the Ts from get_inner_t can differ. I do genuinely want to allow that the two Bazs differ, and the Foos differ, but constrain their Ts to be the same.

I've tried to adapt the answer given, by writing

impl<B1: Baz, B2: Baz< <F as Foo>::T = B1::F::T >> Bar<B1, B2>

But that gives this compile error:

   Compiling type_bindings v0.1.0 (/home/harry/coding/rust_sandbox/type_bindings)
error: expected one of `(`, `,`, `::`, `<`, or `>`, found `=`
  --> src/main.rs:18:38
   |
18 | impl<B1: Baz, B2: Baz< <F as Foo>::T = B1::F::T >> Bar<B1, B2>
   |                                      ^ expected one of `(`, `,`, `::`, `<`, or `>`

error: aborting due to previous error

error: could not compile `type_bindings`

To learn more, run the command again with --verbose.

If this multi-level extraction of associated types not permitted?



from Recent Questions - Stack Overflow https://ift.tt/2ZO4Yp6
https://ift.tt/eA8V8J

No comments:

Post a Comment