>
> There are cases involving closures, generated trampolines, late
> binding and other details that mean that doing this will either
> eliminate many optimization possibilities or restrict the compiler too
> much or cause surprising results. We disabled function comparison for
> just these reasons. It used to work this way, but made closures
> surprising, so we backed out and allow comparison only to nil.


That's interesting. I didn't know that. :)

When I run:

```
func f() {
    x := func() {}
    y := func() {}
    fmt.Printf("%#v %#v %#v %#v\n", x, y, func() {}, func() {})
}

func g() {}

func main() {
    fmt.Printf("%#v %#v %#v %#v\n", f, g, func() {}, func() {})
    f()
}
```

I get:

```
(func())(0x108ac80) (func())(0x108ad40) (func())(0x108ad60)
(func())(0x108ad80)
(func())(0x108ac00) (func())(0x108ac20) (func())(0x108ac40)
(func())(0x108ac60)
```

I don't know where those integer values are coming from, but those are what
I meant by memory addresses. They seem to be unique per function value.
Can't the runtime calculate those same values for comparisons?

In LISP terms, these implementations do something more like `eq`, not
> `equal`. I want to know if the slices or maps are _equivalent_, not if
> they point to identical memory. No one wants this semantics for slice
> equality. Checking if they are equivalent raises difficult issues
> around recursion, slices that point to themselves, and other problems
> that prevent a clean, efficient solution.


Can't the same argument be made for pointer comparisons? Why should we
compare pointer values when doing so won't compare the referenced, logical
values? Because sometimes we want to compare just the pointer values
because it's fast, and pointers are small, and you can conclude logical
equivalence if they're equal. Sometimes shallow/literal comparisons are
useful, and sometimes deep/logical comparisons are useful.

Just as pointer comparisons are shallow, so too are comparisons for types
that contain pointers. I included the Slice1000 example above specifically
to address your point. Based on your argument here, I assume your answer to
the question about `c` in that example would be "yes," however the answer
is no, according to current Go behavior. Comparison of structs containing
pointers does a shallow comparison of the pointer value, not the value it
references. My argument is that under the hood, Go slices work the same way.

I'm proposing a shallow comparison, not a deep comparison, and that's
arguably a feature here. I highlighted the time complexity for a reason,
because I recall someone in the Go Team at one point arguing somewhere that
doing a logical comparison would be too slow, since one of the benefits of
Go comparisons is that their time complexity is small and well-understood.
Checking for equality for your struct-based type won't ever cause your
program to slow or hang; it's "safe."

The point isn't to provide equivalence operations; it's to provide useful
comparison operations that are consistent with the other types' comparison
operations, to make all types consistent and simplify
<https://go.dev/doc/faq#map_keys> the language. We could provide a separate
equivalence operation, perhaps something like `===` that behaves like
`reflect.DeepEquals`, but that's a separate issue. Shallow slice
comparisons *do* allow you to conclude that elements are equal if slices
compare equal, and we can still iterate slices manually to compare elements.

On Mon, May 2, 2022 at 9:58 PM Rob Pike <r...@golang.org> wrote:

> * Functions: Compare the corresponding memory addresses. The time
> complexity is constant.
>
> There are cases involving closures, generated trampolines, late
> binding and other details that mean that doing this will either
> eliminate many optimization possibilities or restrict the compiler too
> much or cause surprising results. We disabled function comparison for
> just these reasons. It used to work this way, but made closures
> surprising, so we backed out and allow comparison only to nil.
>
> * 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.
>
> In LISP terms, these implementations do something more like `eq`, not
> `equal`. I want to know if the slices or maps are _equivalent_, not if
> they point to identical memory. No one wants this semantics for slice
> equality. Checking if they are equivalent raises difficult issues
> around recursion, slices that point to themselves, and other problems
> that prevent a clean, efficient solution.
>
> Believe me, if equality for these types was efficient _and_ useful, it
> would already be done.
>
> -rob
>
> On Tue, May 3, 2022 at 2:41 PM Will Faught <will.fau...@gmail.com> wrote:
> >
> > You seem to have misunderstood the point. It's an idea for changing the
> language. You're just demonstrating the current behavior, which is what
> would be changed. The argument is to make `make([]int, 2) == make([]int,
> 2)` legal, and evaluate to false.
> >
> > On Mon, May 2, 2022 at 8:22 PM Kurtis Rader <kra...@skepticism.us>
> wrote:
> >>
> >> On Mon, May 2, 2022 at 7:44 PM will....@gmail.com <
> will.fau...@gmail.com> wrote:
> >>>
> >>> ```
> >>> 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?
> >>
> >>
> >> No. Did you actually try your hypothetical `make([]int, 2) ==
> make([]int, 2)`? When I do so using the source below this reply the Go
> compiler emits the error "slice can only be compared to nil". Which is what
> I expect given the specification for the Go language. This seems like an
> example of the XY Problem. What caused you to open this thread?
> >>
> >> package main
> >>
> >> import (
> >> "fmt"
> >> )
> >>
> >> func main() {
> >> fmt.Printf("%v\n", make([]int, 2) == make([]int, 2))
> >> }
> >>
> >> --
> >> Kurtis Rader
> >> Caretaker of the exceptional canines Junior and Hank
> >
> > --
> > 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/CAKbcuKheNk99JrYJ8u6knu15LSwf6nZXxD6_UqUOF_1JhFVHjA%40mail.gmail.com
> .
>

-- 
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/CAKbcuKicTHJZZ7yAYKO96MhCPQct%3DQZs07S4%3D-_vXvmoe_ndqA%40mail.gmail.com.

Reply via email to