Skip to content

spec: "strictly comparable" and "type constraints". #59104

Open

Description

@gitspeaks

#1 According to the Language Specification:

A type is strictly comparable if it is comparable and not an interface type nor composed of interface types. Specifically:

Boolean, numeric, string, pointer, and channel types are strictly comparable.
Struct types are strictly comparable if all their field types are strictly comparable.
Array types are strictly comparable if their array element types are strictly comparable.
Type parameters are strictly comparable if all types in their type set are strictly comparable."

Consider changing to:

A type is strictly comparable if it is comparable and not a basic interface type nor composed of 
interface types. Specifically: 

Boolean, numeric, string, pointer, and channel types are strictly comparable. 
Struct types are strictly comparable if all their field types are strictly comparable. 
Array types are strictly comparable if their array element types are strictly comparable. 

Type constraints are strictly comparable if their elements are strictly comparable thus 
Type parameters (not to be confused with Type arguments) are strictly comparable if all 
types in their type set are strictly comparable. 

Rational: By definition “A type constraint is an interface” and the doc explicitly mentions: “strictly comparable type constraint” under "Satisfying a type constraint".

#2 Consider capitalizing each instance of the word "Comparable" where it references the property of comparability, as described in the "Comparison Operators" section. The term "comparable" appears in other contexts, such as "strictly comparable" and the comparable Interface", so due to the repetition of the word, it can be difficult to follow.

#3 Addressing a related but distinct issue, under "General Interfaces" it is stated that: "The type set of a non-interface type term is the set consisting of just that type."

The following example is provided:

// An interface representing only the type int 
type Foo interface { int }

By definition, this interface is a non-basic interface, which means it can only appear in type constraints. However, the rationale for an interface of this form is not immediately apparent. Please clarify in the spec the circumstances in which declaring an interface with a non-interface type term would be sensible.

Activity

  1. ianlancetaylor commented on Mar 17, 2023

    @ianlancetaylor
    Contributor

    CC @griesemer

    1. We don't have to define comparability of interface types that are not basic interface types, as it is invalid to have values of such types. I don't understand the point of your rewrite of the final sentence, about type parameters.

    2. We aren't going to capitalize Comparable in the spec, that is not grammatical English.

    3. The spec needs to define the type set of int in order to define the type set of int | float.

  2. added
    WaitingForInfoIssue is not actionable because of missing required information, which needs to be provided.
    on Mar 17, 2023
  3. gitspeaks commented on Mar 17, 2023

    @gitspeaks
    Author
    1. We don't have to define comparability of interface types that are not basic interface types, as it is 
       invalid to have values of such types.  
    

    The issue is not about defining the comparability of interface types that are not basic, but rather about maintaining consistency in terminology. If "a type is strictly comparable if it is comparable and not an interface type," then how can a "strictly comparable type constraint" exist when a type constraint is an interface?

    I don't understand the point of your rewrite of the final sentence, about type parameters.

    The point is to clarify that in this instance type parameters obtain their type sets from Type constraints (interfaces types that are strictly comparable, as apposed to type argument, such as interface type arguments which are not strictly comparable)

    2. We aren't going to capitalize Comparable in the spec, that is not grammatical English.
    

    In my opinion, the way the word "comparable" is used in the specification strongly suggests a domain-specific term. Its meaning is not immediately obvious (the document even links it to "Comparison Operators"), so I don't see any issue in treating it as a capitalized term. Alternatively, you could write "comparable type." In any case, the goal is to help the reader keep track of which "comparable" is being discussed.

    3. The spec needs to define the type set of `int` in order to define the type set of `int | float`.
    

    Why? Why is it necessary to define the type set of int | float? Why does the compiler even accept:

    type MyType[T int] struct {
            field T
    }
    

    which is exactly:

    type MyType struct {
            field int
    }
    
  4. ianlancetaylor commented on Mar 18, 2023

    @ianlancetaylor
    Contributor

    The issue is not about defining the comparability of interface types that are not basic, but rather about maintaining consistency in terminology. If "a type is strictly comparable if it is comparable and not an interface type," then how can a "strictly comparable type constraint" exist when a type constraint is an interface?

    I see, I missed that you changed the text from referring to a "type parameter" to referring to a "type constraint." I do think that it's important to define when a type parameter is strictly comparable. It's not clear to me whether it is important to define when a type constraint is strictly comparable. Your suggested modified text doesn't explain when a type parameter is strictly comparable. Or so it seems to me.

    ...I don't see any issue in treating it as a capitalized term.

    Are there other such capitalized terms in the spec today? If not, let's not add one.

    Why is it necessary to define the type set of int | float?

    The definition of the type set of T1 | T2 is that it is the union of the type sets of T1 and T2. Therefore, we need to define what those type sets are.

  5. gitspeaks commented on Mar 18, 2023

    @gitspeaks
    Author

    It's not clear to me whether it is important to define when a type constraint is strictly comparable.

    Well, the spec does mention the term "strictly comparable type constraint," so it begs the question, what is it?

    Your suggested modified text doesn't explain when a type parameter is strictly comparable. Or so it seems to me.

    The spec states: "An interface type defines a type set".
    The spec states: "A type constraint is an interface". This implies that a type constraint defines a type set.
    The spec states: "Each type parameter has a corresponding (meta-)type which is called its type constraint". This implies that each type parameter has a type constraint that defines a type set.

    The spec states: "Type parameters are strictly comparable if all types in their type set are strictly comparable." This implies that type parameters are strictly comparable if all the types in the type set defined by their type constraints are strictly comparable.

    What do you call a type constraint that defines a type set where all types are strictly comparable other than a strictly comparable type constraint?

    Are there other such capitalized terms in the spec today? If not, let's not add one.

    Agreed, so I suggest using the term "comparable types" linking to the "Comparison Operators" section:

    Compare:

    Original: "Even though interfaces that are not type parameters are comparable, they are not strictly comparable and therefore they do not implement comparable. However, they satisfy comparable.

    vs.

    Revised: Even though interfaces that are not type parameters are comparable types, they are not strictly comparable and therefore they do not implement the comparable interface. However, they satisfy the comparable interface.

    The definition of the type set of T1 | T2 is that it is the union of the type sets of T1 and T2. Therefore, we need to define what those type sets are.

    It seems to me that type Foo interface { int } is allowed for completeness rather than any practical application. I won't argue with that. However, I do recommend clarifying this point in the spec.

  6. ianlancetaylor commented on Mar 19, 2023

    @ianlancetaylor
    Contributor

    It seems to me that type Foo interface { int } is allowed for completeness rather than any practical application.

    Yes.

    I won't argue with that. However, I do recommend clarifying this point in the spec.

    The spec is intended to be readable but it is not a tutorial.

    I'll leave the other points for @griesemer .

  7. gitspeaks commented on Mar 19, 2023

    @gitspeaks
    Author

    Please consider the following revised statement:

    "Type constraints are deemed strictly comparable if their elements are strictly comparable and the comparable interface is not included. In this case, the associated type parameters are also considered strictly comparable."

    This occurs because incorporating the comparable interface in a type constraint effectively relaxes the constraint, allowing any comparable type as a type argument provided that it implements all other interfaces included in the type constraint.

  8. self-assigned this
    on Mar 20, 2023
  9. added this to the Go1.21 milestone on Mar 20, 2023
  10. griesemer commented on Mar 20, 2023

    @griesemer
    Contributor

    Marked for 1.21 so it remains visible. Not sure yet if we need to make any changes.

  11. added
    NeedsDecisionFeedback is required from experts, contributors, and/or the community before a change can be made.
    and removed
    WaitingForInfoIssue is not actionable because of missing required information, which needs to be provided.
    on Mar 25, 2023
  12. modified the milestones: Go1.21, Go1.22 on Jul 19, 2023
  13. modified the milestones: Go1.22, Go1.23 on Nov 30, 2023
  14. modified the milestones: Go1.23, Go1.24 on Aug 13, 2024
  15. modified the milestones: Go1.24, Go1.25 on Jan 10, 2025
  16. modified the milestones: Go1.25, Go1.26 on Aug 12, 2025
  17. modified the milestones: Go1.26, Go1.27 on Jan 14, 2026
  18. modified the milestones: Go1.27, Go1.28 on Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

DocumentationIssues describing a change to documentation.NeedsDecisionFeedback is required from experts, contributors, and/or the community before a change can be made.

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions