All types should have unrestricted comparisons (`==`, `!=`), but a few 
pre-declared types don't. Adding them would bridge a semantic gap between 
pre-declared and user-declared types, enabling all types to be used as map 
keys, and otherwise make reasoning about them more consistent and intuitive.

For the types that don't yet have unrestricted comparisons:

   - Functions: Compare the corresponding memory addresses. The time 
   complexity is constant.
   - Maps: Compare the corresponding `*runtime.hmap` (pointer) values. The 
   time complexity is constant.
   - Slices: Compare the corresponding `runtime.slice` (non-pointer struct) 
   values. The time complexity is constant.
   
Examples:

```
// Functions

func F1() {}
func F2() {}

var _ = F1 == F1 // True
var _ = F1 != F2 // True

// Maps

var M1 = map[int]int{}
var M2 = map[int]int{}

var _ = M1 == M1 // True
var _ = M1 != M2 // True

// Slices

var S1 = make([]int, 2)
var S2 = make([]int, 2)

var _ = S1 == S1 // True
var _ = S1 != S2 // True

var _ = S1 == S1[:] // True because the lengths, capacities, and pointers 
are equal
var _ = S1 != S1[:1] // True because the lengths aren't equal
var _ = S1[:1] != S1[:1:1] // True because the capacities aren't equal
var _ = S1 != append(S1, 0)[:2:2] // True because the pointers aren't equal
```

Function and map equality are consistent with channel equality, where 
non-nil channels are equal if they were created by the same call to `make`. 
Function values are equal if they were created by the same function literal 
or declaration. Map values are equal if they were created by the same map 
literal or the same call to `make`. Functions that are equal will always 
produce the same outputs and side effects given the same inputs and 
conditions; however, the reverse is not necessarily true. Maps that are 
equal will always contain the same keys and values; however, the reverse is 
not necessarily true.

Slice equality is consistent with map equality. Slice values are equal if 
they have the same array pointer, length, and capacity. Slices that are 
equal will always have equal corresponding elements. However, like maps, 
slices that have equal corresponding elements are not necessarily equal.

This approach to comparisons for functions, maps, and slices makes all 
values of those types immutable, and therefore usable as map keys.

This would obviate the `comparable` constraint, since all type arguments 
would now satisfy it. In my opinion, this would make the language simpler 
and more consistent. Type variables could be used with comparison 
operations without needing to be constrained by `comparable`.

If you think slice equality should incorporate element equality, here's an 
example for you:

```
type Slice1000[T any] struct {
    xs *[1000]T
    len, cap int
}

func (s Slice1000[T]) Get(i int) T {
    // ...
    return s.xs[i]
}

func (s Slice1000[T]) Set(i int, x T) {
    // ...
    s.xs[i] = x
}

var xs1, xs2 [1000]int

var a = Slice1000[int]{&xs1, 1000, 1000}
var b = Slice1000[int]{&xs2, 1000, 1000}
var c = a == b
```

Do you expect `c` to be true? If not (it's false, by the way), then why 
would you expect `make([]int, 2) == make([]int, 2)` to be true?

Any thoughts?

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/8cdc4dae-95f8-4a38-b977-b5b228867c6fn%40googlegroups.com.

Reply via email to