Quoting Andy Balholm (2018-10-20 13:30:58)
> There are some contracts in the draft design that can’t be expressed with the “implements” syntax as it stands. Some would be fairly simple syntax extensions, but others describe the relationship between two types rather than just the operations on a single type. No extension of interfaces (except perhaps generic interfaces with mutually-referential type parameters) can handle those.
>
> The one called convertible is an example of one that would require a fairly trivial extension: adding a way to declare that a method implements a type conversion.
>
> For an example of the other kind, take G from the graph example. I don’t think any of the alternate proposals can handle that situation (at least not nearly as succinctly):
>
> contract G(n Node, e Edge) {
> var _ []Edge = n.Edges()
> var from, to Node = e.Nodes()
> }
The graph example is addressed in the context of my proposal here:
https://gist.github.com/zenhack/ad508d08c72fce6df945a49945ad826d#mutually-referential-type-parameters
Granted, it is slightly more verbose -- but I do not think that the
extra concision for this *one* example in the draft is worth introducing
an entirely new non-orthogonal concept.
The convertible example does not seem especially well motivated to me.
FormatUnsigned is defined like this:
func FormatUnsigned(type T convertible(uint64, T))(v T) string {
return strconv.FormatUint(uint64(v), 10)
}
And then used like:
s := FormatUnsigned(rune)('a')
But why not:
func FormatUnsigned(v uint64) string {
return strconv.FormatUint(v, 10)
}
// ...
s := FormatUnsigned(uint64('a'))
I'm quite willing to discard convertible without a more compelling
example.
> Even if we give up on the ability to define relationships between types, adding extensions for all the other operations that people will want support for will likely take away much of the initial simplicity that makes the “implements” syntax attractive—one trivial extension at a time. The “contract” proposal, on the other hand, is actually a simple, powerful idea; it's working out the implications that ties people’s brains in knots.
Eric has said this elsewhere, but his suggestion (and operator
overloading generally) is not a complete solution (nor is it
intended to be). However, it complements my own proposal (see
above) in a way that allows it to abstract over operators as well as
operators. I haven't seen any *compelling* use cases that can be dealt
with using contracts, but not interfaces + operator overloading.