I like the proposal to use a new, semantically-clear keyword, though arguably delegate is a little too long. And I think overall this is a much nicer proposed syntax than the alternatives you’ve listed (though I didn’t read the original proposal thread).
I have a few quibbles, and a quickly sketched alternative syntax that I believe resolves them:
- The items being delegated (
* or fn foo, fn bar...) should be listed after the delegated-to member, because, to me, the key information in such a declaration is “this trait is implemented by this member,” not the specific names of the members of the trait.
- When members are explicitly listed rather than globbed, the line quickly becomes long and difficult to read.
- The pattern of using a glob but partially overriding it seems potentially confusing.
Here’s my proposal:
We introduce delegate blocks, which are like impl blocks, except that their definitions are “forwarding” rather than from-scratch. A delegate block declaration is the same as an impl block declaration, but uses the delegate keyword in stead of the impl keyword:
delegate TR for S {
....
}
(The reason for introducing a new type of block is twofold: (1) I think that forwarding or delegating is simply very semantically different from implementing, and (2) this prevents any confusion or ambiguity, now or in the future, with the syntax of impl blocks.)
Within the block, members of TR are aliased to members of S, or submembers (recursively):
delegate TR for S {
fn foo = self.foo;
fn bar = self.baz;
fn baz = self.f.g.h.baz; // Equivalent to `impl TR for S { fn baz(args...) { self.f.g.h.baz(args...) } }`
}
When the names of the members of TR being aliased match the names of members of S or some subobject, the following syntax may be used:
delegate TR for S {
fn bar = self.f.*; // Equivalent to `fn bar = self.f.bar;`
type Item = <S as F>::G::*; // Equivalent to `type Item = <S as F>::G::Item;`
[fn foo, const MAX] = self.*; // Equivalent to `fn foo = self.foo; const MAX = self.MAX;`
}
To delegate an entire trait to a member of S, additional syntactic sugar (replacing the entire block with a single alias) can be used:
delegate TR for S = S.f;
This would be equivalent to:
delegate TR for S {
[fn foo, fn bar, ...... (all members listed explicitly)] = S.f.*;
}
It is an error to use this non-block sugared syntax in conjunction with any other delegation on TR.