I think having something like Rust's Trait<AssocType = T>
associated type constraint sugar would be great. If we allowed both same-type and protocol constraint bindings inside angle brackets, then it seems to me like it should be possible to express all constraints relative to the opaque result type without resorting to the where
clause; you can express protocol constraints on the opaque type itself as a protocol composition, then require all its associated type constraints to use the new sugar to be expressed under angle brackets:
func map<U>(_ f: (Element) -> U) -> opaque Collection<Element == U>
I believe Rust's impl Trait
feature doesn't allow you to express constraints on the unnamed type independent of the trait constraint either. If we go with the "multiple ->
arrows" syntax for conditional conformances, this also makes the notation a bit more manageable IMO, since the conditional constraints are detangled from the implied constraints on the output type:
func reversed() -> opaque BidirectionalCollection<Element == Element>
-> opaque RandomAccessCollection<Element == Element> where Self: RandomAccessCollection
-> /* etc. */
I guess writing Foo == Foo
is a bit weird (taking the LHS inside brackets to always refer to an associated type like in Rust), but Rust users don't seem to mind?
edit: Ah, the one thing you still wouldn't be able to spell without mentioning the opaque type is a same-type constraint between two associated types of the opaque type.