Allow type placeholder for item signatures if they constrain the associated types

I tried to write following code which seems to be disallowed by Rust:

trait Foo {
    type Foo;
    fn get_foo(&self) -> &Self::Foo;
}

/* Not allowed
trait Bar1: Foo<Foo = Option<_>> {
    fn bar(&self) -> bool {
        self.get_foo().is_some()
    }
}
*/

/* Verbose as pollutes all usage of this trait */
trait Bar2<S>: Foo<Foo = Option<S>> {
    fn bar(&self) -> bool {
        self.get_foo().is_some()
    }
}

/* Less verbose for my case but awkward and more of a workaround */
trait Bar3: Foo {
    fn bar<S>(&self) -> bool where Self: Foo<Foo = Option<S>> {
        self.get_foo().is_some()
    }
}

Right, you’ve invented a nicer syntax that Rust doesn’t support.

trait Bar2<S>: Foo<Foo = Option<S>> 

This means “for each S, make a new version of this trait”, which in this case is necessary, because every Option<S> may have different layout, and a different way of encoding Some, so every call to is_some() may be different. Rust just likes to be explicit about it.

Yet :wink: Tracking issue for trait aliases · Issue #41517 · rust-lang/rust · GitHub

3 Likes

This means “for each S, make a new version of this trait”, which in this case is necessary, because every Option<S> may have different layout, and a different way of encoding Some, so every call to is_some() may be different. Rust just likes to be explicit about it.

I'm not sure I'm following. Since type can implement Foo only once Self::Foo needs to be known during implementation anyway. All Foo = Option<_> does is restrict what Bar2 can be implemented for. The only thing that would be different as far as I can see is that default implementation needs to be generated - but from language user perspective that's an implementation detail.

BTW, I mixed up users/internals forums and I thought your post was a question, not a proposal.

I was referring to monomorphisation. There has to be a different is_some() call for Option<&Foo> (null check) and Option<Foo> (extra boolean field). In some way it is an implementation detail, but also it’s visible in the syntax when that approach is used.

Doesn’t it need to happen anyway if the trait consumes objects (fn foo(self, foo: Self)) as Self might take different amount of space? Self::Foo is dependent type so if you monomorphise in type of object implementing trait the dependent trait monomorphosation shouldn’t be much different I think.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.