Description
This is an attempt at defining possible implementation of anonymous fields (inspired by Go). There are some "obvious" design choices and some not-so-obvious ones involved. The following is what I hope to be a "reasonable" combination. Here goes...
The idea is to allow fields without a name, e.g.:
struct Foo {
Bar, // Anonymous field
Baz, // Another anonymous field
named: int // Named field
}
It is illegal to have two anonymous fields with the same type (as that would be ambiguous).
Members
Writing foo.Bar.member
would access members of the Bar
structure. This is always legal (since there's only one Bar
member).
Writing foo.member
will access a member explicitly declared in Foo
, if there is one. Otherwise, of there's only one anonymous member providing the member, it is accessed. Otherwise (if there's no such anonymous field, or if there's more than one), it is an error.
Methods
Writing foo.Bar.method(...)
would invoke the method on the Bar
field. This is always legal (since there's only one Bar
member).
Writing foo.method(...)
works similarly to accessing a member - if there's a method explicitly declared for Foo
, it is called; if there's only one anonymous field providing it, it is called; otherwise, it is an error.
Design choice A: When a method of an anonymous field is invoked, all self.*
or function(self)
accesses are interpreted using the type of the anonymous field. For example, if Foo
provides a foo
method, and Bar
also provides a foo
method, and Bar.bar
invokes self.foo
, then Foo.bar
will invoke Bar.foo
, not Foo.foo
.
Traits
Design choice B: There are no implicit traits for Foo
.
When implementing a trait for Foo
, it is allowed to omit the implementation of a function if it is unambiguously available by any anonymous field. So, if Bar
implements a trait, one should typically simply say impl Trait for Foo {}
and be done.
However, if an explicit function is defined inside the impl Trait for Foo { ... }
block, it would be used instead of any anonymous field function. This is consistent with the function calling semantics above. For example, it may be required to specify a function if it is provided by more than one anonymous field.
Access
Design choice C: Public/private control of members and methods accessed via the anonymous field is inherited from the type of the anonymous field. That is, Foo
gets no special access rights to the internals of Bar
.
Diamonds
Design choice D: If both Bar
and Baz
have an anonymous field called Qux
, then there are two separate instances of Qux
- foo.Bar.Qux...
and foo.Baz.Qux...
. This is consistent with reusing the compiled version of anonymous field functions, and avoids the nastiness involved with the diamond multiple-inheritance pattern. So, no equivalent to C++'s "virtual inheritance".
Alternatives
An alternative to anonymous fields is to provide a delegate
syntax, allowing delegating certain methods to (named) fields. Delegation would also need to work for members. The syntax for delegation would be tricky as we don't want to repeat the whole list of methods/members on the one hand, but would need to provide some control on the other hand. Possibly delegate * to field_name
would be enough, but that is essentially the same having anonymous fields.
Other issues?
The above design choices are made with an eye for a useful simple semantics combined with a simple vtable-based implementation. This doesn't make them "right" and I probably missed some issues...