-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
Background
Out of caution over backward compatibility of features introduced with generics, with little discussion with the community when changing a major proposal that had already been accepted, Go 1.18 defined the predeclared constraint comparable
to be "the set of all non-interface types that are comparable." The majority of the conversation motivating the "non-interface" portion of that definition occurred in #50646 and #49587.
That interface types are comparable but not comparable
is a significant pain point for a number of otherwise fine uses of generics: e.g., one cannot use x/exp/maps algorithms on map types which have reflect.Type
as keys. #52474 (now retracted) was proposed to alleviate this problem, noting that the precise definition of comparable
should include types like [1]reflect.Type
, which is an array type supporting ==
rather than an interface type. A significant portion of the comments on that proposal noted that the entire motivation for the proposal is the inconsistency between "comparable" and comparable
.
Proposal
The proposal here is to allow interface types to instantiate type parameters constrained by comparable
. In essence, I propose to remove the term "non-interface" from the definition of comparable
, so that "comparable" and comparable
mean the same thing in every context in Go.
@atdiar points out that other language in the spec would produce contradictions following that simple change. This proposal would additionally require a change to the definition of type sets or the definition of implementing interfaces, likely splitting either or both into two senses for type parameters and otherwise.
A consequence of this proposal is that it becomes possible to write generic code using comparable
which panics on comparison with non-comparable concrete types. That is an aspect of the type system which has existed since long before Go 1.0; in particular, see @nield's demonstration that the results are very similar to the situation we've always had. What we gain is the ability to write code generic over all comparable types, rather than most of them with no solution for the remainder.
For the concrete change to the Go specification that I propose to implement this, see #52509 (comment). It is not the only possible approach. @jimmyfrasche proposes #52509 (comment), and @Merovius proposes #52509 (comment) with an enumeration of examples at #52509 (comment).
Related Proposals
- proposal: spec: permit values to have type "comparable" #51338
- proposal: spec: add new constraint kind satisfied by types that support == (including interface types) #52531
- proposal: type parameters are comparable unless they exclude comparable types #52614
- proposal: spec: allow values of type comparable #52624
- proposal: spec: comparable as a case of a generalized definition of basic interfaces #53734