mirror of https://github.com/golang/go.git
spec: introduce notion of strict comparability
- Rephrase the notion of "comparability" from a property of values (operands) to a property of types and adjust dependent prose. - Introduce the notion of "strict comparability". - Fix the definitions of comparability for type interfaces and type parameters. - Define the predeclared identifier "comparable" as stricly comparable. These changes address existing problems in the spec as outlined in the section on "Related spec issues" in issue #56548. For #56548. Change-Id: Ibc8c2f36d92857a5134eadc18358624803d3dd21 Reviewed-on: https://go-review.googlesource.com/c/go/+/457095 Reviewed-by: Ian Lance Taylor <iant@google.com> Reviewed-by: Matthew Dempsky <mdempsky@google.com> TryBot-Bypass: Robert Griesemer <gri@google.com> Reviewed-by: Robert Findley <rfindley@google.com> Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
parent
cb07765045
commit
ffefcd360b
|
|
@ -1,6 +1,6 @@
|
||||||
<!--{
|
<!--{
|
||||||
"Title": "The Go Programming Language Specification",
|
"Title": "The Go Programming Language Specification",
|
||||||
"Subtitle": "Version of November 21, 2022",
|
"Subtitle": "Version of December 14, 2022",
|
||||||
"Path": "/ref/spec"
|
"Path": "/ref/spec"
|
||||||
}-->
|
}-->
|
||||||
|
|
||||||
|
|
@ -2684,18 +2684,17 @@ other interfaces based on their type sets. But this should get us going for now.
|
||||||
The <a href="#Predeclared_identifiers">predeclared</a>
|
The <a href="#Predeclared_identifiers">predeclared</a>
|
||||||
<a href="#Interface_types">interface type</a> <code>comparable</code>
|
<a href="#Interface_types">interface type</a> <code>comparable</code>
|
||||||
denotes the set of all non-interface types that are
|
denotes the set of all non-interface types that are
|
||||||
<a href="#Comparison_operators">comparable</a>. Specifically,
|
<a href="#Comparison_operators">strictly comparable</a>. Specifically,
|
||||||
a type <code>T</code> implements <code>comparable</code> if:
|
a type <code>T</code> implements <code>comparable</code> if:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<code>T</code> is not an interface type and <code>T</code> supports the operations
|
<code>T</code> is not an interface type and <code>T</code> is strictly comparable; or
|
||||||
<code>==</code> and <code>!=</code>; or
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<code>T</code> is an interface type and each type in <code>T</code>'s
|
<code>T</code> is an interface type and each type in <code>T</code>'s
|
||||||
<a href="#Interface_types">type set</a> implements <code>comparable</code>.
|
<a href="#Interface_types">type set</a> is strictly comparable.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
@ -2707,12 +2706,13 @@ Even though interfaces that are not type parameters can be
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
int // implements comparable
|
int // implements comparable (int is strictly comparable)
|
||||||
[]byte // does not implement comparable (slices cannot be compared)
|
[]byte // does not implement comparable (slices cannot be compared)
|
||||||
interface{} // does not implement comparable (see above)
|
interface{} // does not implement comparable (see above)
|
||||||
interface{ ~int | ~string } // type parameter only: implements comparable
|
interface{ ~int | ~string } // type parameter only: implements comparable (int, string types are stricly comparable)
|
||||||
interface{ comparable } // type parameter only: implements comparable
|
interface{ comparable } // type parameter only: implements comparable (comparable implements itself)
|
||||||
interface{ ~int | ~[]byte } // type parameter only: does not implement comparable (not all types in the type set are comparable)
|
interface{ ~int | ~[]byte } // type parameter only: does not implement comparable (slices are not comparable)
|
||||||
|
interface{ ~struct{ any } } // type parameter only: does not implement comparable (field any is not strictly comparable)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -5019,69 +5019,71 @@ to the type of the second operand, or vice versa.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The equality operators <code>==</code> and <code>!=</code> apply
|
The equality operators <code>==</code> and <code>!=</code> apply
|
||||||
to operands that are <i>comparable</i>.
|
to operands of <i>comparable</i> types.
|
||||||
The ordering operators <code><</code>, <code><=</code>, <code>></code>, and <code>>=</code>
|
The ordering operators <code><</code>, <code><=</code>, <code>></code>, and <code>>=</code>
|
||||||
apply to operands that are <i>ordered</i>.
|
apply to operands of <i>ordered</i> types.
|
||||||
These terms and the result of the comparisons are defined as follows:
|
These terms and the result of the comparisons are defined as follows:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
Boolean values are comparable.
|
Boolean types are comparable.
|
||||||
Two boolean values are equal if they are either both
|
Two boolean values are equal if they are either both
|
||||||
<code>true</code> or both <code>false</code>.
|
<code>true</code> or both <code>false</code>.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
Integer values are comparable and ordered, in the usual way.
|
Integer types are comparable and ordered.
|
||||||
|
Two integer values are compared in the usual way.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
Floating-point values are comparable and ordered,
|
Floating-point types are comparable and ordered.
|
||||||
as defined by the IEEE-754 standard.
|
Two floating-point values are compared as defined by the IEEE-754 standard.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
Complex values are comparable.
|
Complex types are comparable.
|
||||||
Two complex values <code>u</code> and <code>v</code> are
|
Two complex values <code>u</code> and <code>v</code> are
|
||||||
equal if both <code>real(u) == real(v)</code> and
|
equal if both <code>real(u) == real(v)</code> and
|
||||||
<code>imag(u) == imag(v)</code>.
|
<code>imag(u) == imag(v)</code>.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
String values are comparable and ordered, lexically byte-wise.
|
String types are comparable and ordered.
|
||||||
|
Two string values are compared lexically byte-wise.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
Pointer values are comparable.
|
Pointer types are comparable.
|
||||||
Two pointer values are equal if they point to the same variable or if both have value <code>nil</code>.
|
Two pointer values are equal if they point to the same variable or if both have value <code>nil</code>.
|
||||||
Pointers to distinct <a href="#Size_and_alignment_guarantees">zero-size</a> variables may or may not be equal.
|
Pointers to distinct <a href="#Size_and_alignment_guarantees">zero-size</a> variables may or may not be equal.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
Channel values are comparable.
|
Channel types are comparable.
|
||||||
Two channel values are equal if they were created by the same call to
|
Two channel values are equal if they were created by the same call to
|
||||||
<a href="#Making_slices_maps_and_channels"><code>make</code></a>
|
<a href="#Making_slices_maps_and_channels"><code>make</code></a>
|
||||||
or if both have value <code>nil</code>.
|
or if both have value <code>nil</code>.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
Interface values are comparable.
|
Interface types that are not type parameters are comparable.
|
||||||
Two interface values are equal if they have <a href="#Type_identity">identical</a> dynamic types
|
Two interface values are equal if they have <a href="#Type_identity">identical</a> dynamic types
|
||||||
and equal dynamic values or if both have value <code>nil</code>.
|
and equal dynamic values or if both have value <code>nil</code>.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
A value <code>x</code> of non-interface type <code>X</code> and
|
A value <code>x</code> of non-interface type <code>X</code> and
|
||||||
a value <code>t</code> of interface type <code>T</code> are comparable when values
|
a value <code>t</code> of interface type <code>T</code> can be compared
|
||||||
of type <code>X</code> are comparable and
|
if type <code>X</code> is comparable and
|
||||||
<code>X</code> <a href="#Implementing_an_interface">implements</a> <code>T</code>.
|
<code>X</code> <a href="#Implementing_an_interface">implements</a> <code>T</code>.
|
||||||
They are equal if <code>t</code>'s dynamic type is identical to <code>X</code>
|
They are equal if <code>t</code>'s dynamic type is identical to <code>X</code>
|
||||||
and <code>t</code>'s dynamic value is equal to <code>x</code>.
|
and <code>t</code>'s dynamic value is equal to <code>x</code>.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
Struct values are comparable if all their fields are comparable.
|
Struct types are comparable if all their field types are comparable.
|
||||||
Two struct values are equal if their corresponding
|
Two struct values are equal if their corresponding
|
||||||
non-<a href="#Blank_identifier">blank</a> field values are equal.
|
non-<a href="#Blank_identifier">blank</a> field values are equal.
|
||||||
The fields are compared in source order, and comparison stops as
|
The fields are compared in source order, and comparison stops as
|
||||||
|
|
@ -5089,23 +5091,27 @@ These terms and the result of the comparisons are defined as follows:
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
Array values are comparable if values of the array element type are comparable.
|
Array types are comparable if their array element types are comparable.
|
||||||
Two array values are equal if their corresponding element values are equal.
|
Two array values are equal if their corresponding element values are equal.
|
||||||
The elements are compared in ascending index order, and comparison stops
|
The elements are compared in ascending index order, and comparison stops
|
||||||
as soon as two element values differ (or all elements have been compared).
|
as soon as two element values differ (or all elements have been compared).
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
Type parameters are comparable if they are strictly comparable (see below).
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
A comparison of two interface values with identical dynamic types
|
A comparison of two interface values with identical dynamic types
|
||||||
causes a <a href="#Run_time_panics">run-time panic</a> if values
|
causes a <a href="#Run_time_panics">run-time panic</a> if that type
|
||||||
of that type are not comparable. This behavior applies not only to direct interface
|
is not comparable. This behavior applies not only to direct interface
|
||||||
value comparisons but also when comparing arrays of interface values
|
value comparisons but also when comparing arrays of interface values
|
||||||
or structs with interface-valued fields.
|
or structs with interface-valued fields.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Slice, map, and function values are not comparable.
|
Slice, map, and function types are not comparable.
|
||||||
However, as a special case, a slice, map, or function value may
|
However, as a special case, a slice, map, or function value may
|
||||||
be compared to the predeclared identifier <code>nil</code>.
|
be compared to the predeclared identifier <code>nil</code>.
|
||||||
Comparison of pointer, channel, and interface values to <code>nil</code>
|
Comparison of pointer, channel, and interface values to <code>nil</code>
|
||||||
|
|
@ -5126,6 +5132,30 @@ var (
|
||||||
)
|
)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
A type is <i>strictly comparable</i> if it is comparable and not an interface
|
||||||
|
type nor composed of interface types.
|
||||||
|
Specifically:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Boolean, numeric, string, pointer, and channel types are strictly comparable.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
Struct types are strictly comparable if all their field types are strictly comparable.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
Array types are strictly comparable if their array element types are strictly comparable.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
Type parameters are strictly comparable if all types in their type set are strictly comparable.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<h3 id="Logical_operators">Logical operators</h3>
|
<h3 id="Logical_operators">Logical operators</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue