Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-29 Thread tapi...@gmail.com


On Thursday, February 29, 2024 at 7:04:14 PM UTC+8 Axel Wagner wrote:

Yes. It means "violating a rule, without setting a precedent for future 
violations".

One of the main objections to the loop variable change has been the 
breaking of compatibility and the fear of setting a precedent for that 
happening in the future. The design doc for it 

 
had this to say:

In the Go 2 transitions document 

 
we gave the general rule that language redefinitions like what we just 
described are not permitted, giving this very proposal as an example of 
something that violates the general rule. We still believe that that is the 
right general rule, but we have come to also believe that the for loop 
variable case is strong enough to motivate a one-time exception to that 
rule. Loop variables being per-loop instead of per-iteration is the only 
design decision we know of in Go that makes programs incorrect more often 
than it makes them correct. Since it is the only such design decision, we 
do not see any plausible candidates for additional exceptions.


This is making it abundantly clear, that the loop var change is a one-time 
exception, because there is a strong case for it. And that it does not set 
a precedent for further such changes. When this concern was brought up 
repeatedly, that was my (and other's) response as well 
.

So, if nothing else, doing another one of these would lose considerable 
good-will and trust with the community, because it would mean that our 
promise that this was a one-time exception was a lie.

Now, you and me both where part of that discussion. And at the time you 
made an argument, among other things, based on compatibility. e.g. in this 
comment 

That is two surprises for many people. Several people said the two cases 
are artificial or "intentionally confusing programs". I'm speechless on 
such non-serious attitudes. I can't believe that the bar to keep 
backward-compatibility is down to such a low level.

 
And in this comment 
, this 
comment  
and in this comment 


If backward-compatibility and expectation breaking is not relevant, then 
okay, it is not relevant.

 
So, I find the fact that you are now trying to establish the loop variable 
change as precedent for breaking compatibility - despite knowing full well, 
that it came with a promise not to do it again - pretty frustrating. It 
seems to me that, because you did not get your will at the time, you are 
now bringing it up to troll unrelated conversations. With no actually 
coherent position.

And so your "one-sentence emoticon" message is neither charming, clever, 
witty nor funny. It's simply disrespectful.



 


On Thu, Feb 29, 2024 at 10:24 AM tapi...@gmail.com  
wrote:



On Thursday, February 29, 2024 at 3:14:40 PM UTC+8 Axel Wagner wrote:

The loop var change *does* break compatibility. And it did so knowingly and 
- as clearly explained - was an exception.
Stop arguing in bad faith.


An exception.
:D 
 


On Thu, Feb 29, 2024 at 7:03 AM tapi...@gmail.com  wrote:



On Wednesday, February 28, 2024 at 3:19:37 PM UTC+8 Axel Wagner wrote:

That would break backwards compatibility, though. And it would be a 
re-definition (i.e. existing code would compile, but behave differently at 
runtime) and is hence not allowed even under the Go 2 transition rules.


With Go version specified, nothing can be broken. For example, the loop var 
change in Go 1.22 doesn't break backwards compatibility. (Though this is 
not my opinion, ;D)
 

I'm also not sure you can exclude *all* pointers to zero-sized variables. 
Note that `[0]T` is also zero-sized and you can convert slices (even empty 
ones) into array-pointers. And you can take the address of struct fields.

All of this to solve an honestly pretty small issue. It's a corner, yes. 
But it isn't a particularly sharp corner.

On Wed, Feb 28, 2024 at 8:06 AM 'Brian Candler' via golang-nuts <
golan...@googlegroups.com> wrote:

> let's consider the two possible definitions:
>
> 1. Pointers to distinct zero-size variables are equal: [...]
> 2. Pointers to distinct zero-size variables are not equal:

Another possibility:

3. Equality comparisons between pointers to zero-size variables are 
forbidden at compile time.
3a. If you wrap two such values in interfaces and try to compare them, then 
you get a runtime panic, same as certain cases today 
.

Indeed, what if it were forbidden to take a pointer to a zero-sized 

Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-29 Thread tapi...@gmail.com


On Thursday, February 29, 2024 at 3:14:40 PM UTC+8 Axel Wagner wrote:

The loop var change *does* break compatibility. And it did so knowingly and 
- as clearly explained - was an exception.
Stop arguing in bad faith.


An exception.
:D 
 


On Thu, Feb 29, 2024 at 7:03 AM tapi...@gmail.com  wrote:



On Wednesday, February 28, 2024 at 3:19:37 PM UTC+8 Axel Wagner wrote:

That would break backwards compatibility, though. And it would be a 
re-definition (i.e. existing code would compile, but behave differently at 
runtime) and is hence not allowed even under the Go 2 transition rules.


With Go version specified, nothing can be broken. For example, the loop var 
change in Go 1.22 doesn't break backwards compatibility. (Though this is 
not my opinion, ;D)
 

I'm also not sure you can exclude *all* pointers to zero-sized variables. 
Note that `[0]T` is also zero-sized and you can convert slices (even empty 
ones) into array-pointers. And you can take the address of struct fields.

All of this to solve an honestly pretty small issue. It's a corner, yes. 
But it isn't a particularly sharp corner.

On Wed, Feb 28, 2024 at 8:06 AM 'Brian Candler' via golang-nuts <
golan...@googlegroups.com> wrote:

> let's consider the two possible definitions:
>
> 1. Pointers to distinct zero-size variables are equal: [...]
> 2. Pointers to distinct zero-size variables are not equal:

Another possibility:

3. Equality comparisons between pointers to zero-size variables are 
forbidden at compile time.
3a. If you wrap two such values in interfaces and try to compare them, then 
you get a runtime panic, same as certain cases today 
.

Indeed, what if it were forbidden to take a pointer to a zero-sized 
variable in the first place? There is nothing to point at, after all.

On Wednesday 28 February 2024 at 07:17:24 UTC+7 Brien Colwell wrote:

I think the surprising part is that the comparison result can change for 
the same values because of the assumption that pointers never change. This 
is implied by the spec but easy to miss.

"Pointers to distinct zero-size variables may or may not be equal."
"Pointers to distinct zero-size variables may or may not be equal and the 
results may or may not be repeatable in any context."

Agree once a programmer is aware of the behavior it can be avoided.

Best,
Brien


On Feb 27, 2024, at 3:06 PM, 'Axel Wagner' via golang-nuts <
golan...@googlegroups.com> wrote:

On Tue, Feb 27, 2024 at 8:19 PM Marvin Renich  wrote:

Prior to generics, the type of the
arguments to == were easily known to the programmer, and so it was
obvious when this "undefined" exception would raise its ugly head, and
you just didn't use it for empty struct types.  But now, with generics,
this can only be classified as a glaring BUG in the spec.


There is pretty much a 0% chance that we'd change the spec in this regard, 
at this point. It would mean that variable declarations like 
`[1<<30]struct{}` would have to allocate huge chunks of heap, to ensure 
that different index-expressions can have different addresses. And while 
there shouldn't be any code relying on that not happening for correctness, 
there is definitely code out there relying on it for performance (e.g. 
there is a pattern of adding struct fields like `_ [0]func()` to ensure a 
type is not comparable - such a struct would now change alignment and size).

The optimization that variables of zero size can re-use the same address 
has been in Go since before Go 1. Given this, it is pretty much implied 
that comparison of those pointers will sometimes have weird results - the 
only question is, *which* results are weird. I agree that this is one of 
the weirder cases. But I don't think we can practically define `==` for 
pointers to zero-sized variables.

I'll also point out that for generics specifically, I'm not sure *any* 
action would have a practical effect. If the type argument is not 
statically known, we also can't special-case it to take into account that 
it's a pointer to a zero-sized variable. Note that the triggered 
optimization isn't necessarily "these are pointers to zero-sized variables, 
hence I can do whatever I want" - it's "these are pointers to distinct 
variables, hence I can assume they are unequal". That is a generally useful 
optimization and it would still be applied to generic code.

How can a programmer count on x == y having any meaning at all in code like 
this:

func IsEqual[T comparable](x, y T) bool {
return x == y
}

if the definition of == for empty structs is undefined?


The result is defined for empty structs, just not for *pointers* to empty 
structs.
Note that `==` has other edge-cases as well. In particular, for floating 
point/complex type arguments, `==` is irreflexive (e.g. NaN is unequal to 
itself).
I'm not sure that pointers to zero-sized variables make this significantly 
worse.
 

If we can at least agree that this ambiguity is no longer desirable,


I don't think we can 

Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-28 Thread 'Axel Wagner' via golang-nuts
The loop var change *does* break compatibility. And it did so knowingly and
- as clearly explained - was an exception.
Stop arguing in bad faith.

On Thu, Feb 29, 2024 at 7:03 AM tapi...@gmail.com 
wrote:

>
>
> On Wednesday, February 28, 2024 at 3:19:37 PM UTC+8 Axel Wagner wrote:
>
> That would break backwards compatibility, though. And it would be a
> re-definition (i.e. existing code would compile, but behave differently at
> runtime) and is hence not allowed even under the Go 2 transition rules.
>
>
> With Go version specified, nothing can be broken. For example, the loop
> var change in Go 1.22 doesn't break backwards compatibility. (Though this
> is not my opinion, ;D)
>
>
> I'm also not sure you can exclude *all* pointers to zero-sized variables.
> Note that `[0]T` is also zero-sized and you can convert slices (even empty
> ones) into array-pointers. And you can take the address of struct fields.
>
> All of this to solve an honestly pretty small issue. It's a corner, yes.
> But it isn't a particularly sharp corner.
>
> On Wed, Feb 28, 2024 at 8:06 AM 'Brian Candler' via golang-nuts <
> golan...@googlegroups.com> wrote:
>
> > let's consider the two possible definitions:
> >
> > 1. Pointers to distinct zero-size variables are equal: [...]
> > 2. Pointers to distinct zero-size variables are not equal:
>
> Another possibility:
>
> 3. Equality comparisons between pointers to zero-size variables are
> forbidden at compile time.
> 3a. If you wrap two such values in interfaces and try to compare them,
> then you get a runtime panic, same as certain cases today
> .
>
> Indeed, what if it were forbidden to take a pointer to a zero-sized
> variable in the first place? There is nothing to point at, after all.
>
> On Wednesday 28 February 2024 at 07:17:24 UTC+7 Brien Colwell wrote:
>
> I think the surprising part is that the comparison result can change for
> the same values because of the assumption that pointers never change. This
> is implied by the spec but easy to miss.
>
> "Pointers to distinct zero-size variables may or may not be equal."
> "Pointers to distinct zero-size variables may or may not be equal and the
> results may or may not be repeatable in any context."
>
> Agree once a programmer is aware of the behavior it can be avoided.
>
> Best,
> Brien
>
>
> On Feb 27, 2024, at 3:06 PM, 'Axel Wagner' via golang-nuts <
> golan...@googlegroups.com> wrote:
>
> On Tue, Feb 27, 2024 at 8:19 PM Marvin Renich  wrote:
>
> Prior to generics, the type of the
> arguments to == were easily known to the programmer, and so it was
> obvious when this "undefined" exception would raise its ugly head, and
> you just didn't use it for empty struct types.  But now, with generics,
> this can only be classified as a glaring BUG in the spec.
>
>
> There is pretty much a 0% chance that we'd change the spec in this regard,
> at this point. It would mean that variable declarations like
> `[1<<30]struct{}` would have to allocate huge chunks of heap, to ensure
> that different index-expressions can have different addresses. And while
> there shouldn't be any code relying on that not happening for correctness,
> there is definitely code out there relying on it for performance (e.g.
> there is a pattern of adding struct fields like `_ [0]func()` to ensure a
> type is not comparable - such a struct would now change alignment and size).
>
> The optimization that variables of zero size can re-use the same address
> has been in Go since before Go 1. Given this, it is pretty much implied
> that comparison of those pointers will sometimes have weird results - the
> only question is, *which* results are weird. I agree that this is one of
> the weirder cases. But I don't think we can practically define `==` for
> pointers to zero-sized variables.
>
> I'll also point out that for generics specifically, I'm not sure *any*
> action would have a practical effect. If the type argument is not
> statically known, we also can't special-case it to take into account that
> it's a pointer to a zero-sized variable. Note that the triggered
> optimization isn't necessarily "these are pointers to zero-sized variables,
> hence I can do whatever I want" - it's "these are pointers to distinct
> variables, hence I can assume they are unequal". That is a generally useful
> optimization and it would still be applied to generic code.
>
> How can a programmer count on x == y having any meaning at all in code
> like this:
>
> func IsEqual[T comparable](x, y T) bool {
> return x == y
> }
>
> if the definition of == for empty structs is undefined?
>
>
> The result is defined for empty structs, just not for *pointers* to empty
> structs.
> Note that `==` has other edge-cases as well. In particular, for floating
> point/complex type arguments, `==` is irreflexive (e.g. NaN is unequal to
> itself).
> I'm not sure that pointers to zero-sized variables make this significantly
> worse.
>
>
> If we can at least agree that this 

Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-28 Thread tapi...@gmail.com


On Wednesday, February 28, 2024 at 3:19:37 PM UTC+8 Axel Wagner wrote:

That would break backwards compatibility, though. And it would be a 
re-definition (i.e. existing code would compile, but behave differently at 
runtime) and is hence not allowed even under the Go 2 transition rules.


With Go version specified, nothing can be broken. For example, the loop var 
change in Go 1.22 doesn't break backwards compatibility. (Though this is 
not my opinion, ;D)
 

I'm also not sure you can exclude *all* pointers to zero-sized variables. 
Note that `[0]T` is also zero-sized and you can convert slices (even empty 
ones) into array-pointers. And you can take the address of struct fields.

All of this to solve an honestly pretty small issue. It's a corner, yes. 
But it isn't a particularly sharp corner.

On Wed, Feb 28, 2024 at 8:06 AM 'Brian Candler' via golang-nuts <
golan...@googlegroups.com> wrote:

> let's consider the two possible definitions:
>
> 1. Pointers to distinct zero-size variables are equal: [...]
> 2. Pointers to distinct zero-size variables are not equal:

Another possibility:

3. Equality comparisons between pointers to zero-size variables are 
forbidden at compile time.
3a. If you wrap two such values in interfaces and try to compare them, then 
you get a runtime panic, same as certain cases today 
.

Indeed, what if it were forbidden to take a pointer to a zero-sized 
variable in the first place? There is nothing to point at, after all.

On Wednesday 28 February 2024 at 07:17:24 UTC+7 Brien Colwell wrote:

I think the surprising part is that the comparison result can change for 
the same values because of the assumption that pointers never change. This 
is implied by the spec but easy to miss.

"Pointers to distinct zero-size variables may or may not be equal."
"Pointers to distinct zero-size variables may or may not be equal and the 
results may or may not be repeatable in any context."

Agree once a programmer is aware of the behavior it can be avoided.

Best,
Brien


On Feb 27, 2024, at 3:06 PM, 'Axel Wagner' via golang-nuts <
golan...@googlegroups.com> wrote:

On Tue, Feb 27, 2024 at 8:19 PM Marvin Renich  wrote:

Prior to generics, the type of the
arguments to == were easily known to the programmer, and so it was
obvious when this "undefined" exception would raise its ugly head, and
you just didn't use it for empty struct types.  But now, with generics,
this can only be classified as a glaring BUG in the spec.


There is pretty much a 0% chance that we'd change the spec in this regard, 
at this point. It would mean that variable declarations like 
`[1<<30]struct{}` would have to allocate huge chunks of heap, to ensure 
that different index-expressions can have different addresses. And while 
there shouldn't be any code relying on that not happening for correctness, 
there is definitely code out there relying on it for performance (e.g. 
there is a pattern of adding struct fields like `_ [0]func()` to ensure a 
type is not comparable - such a struct would now change alignment and size).

The optimization that variables of zero size can re-use the same address 
has been in Go since before Go 1. Given this, it is pretty much implied 
that comparison of those pointers will sometimes have weird results - the 
only question is, *which* results are weird. I agree that this is one of 
the weirder cases. But I don't think we can practically define `==` for 
pointers to zero-sized variables.

I'll also point out that for generics specifically, I'm not sure *any* 
action would have a practical effect. If the type argument is not 
statically known, we also can't special-case it to take into account that 
it's a pointer to a zero-sized variable. Note that the triggered 
optimization isn't necessarily "these are pointers to zero-sized variables, 
hence I can do whatever I want" - it's "these are pointers to distinct 
variables, hence I can assume they are unequal". That is a generally useful 
optimization and it would still be applied to generic code.

How can a programmer count on x == y having any meaning at all in code like 
this:

func IsEqual[T comparable](x, y T) bool {
return x == y
}

if the definition of == for empty structs is undefined?


The result is defined for empty structs, just not for *pointers* to empty 
structs.
Note that `==` has other edge-cases as well. In particular, for floating 
point/complex type arguments, `==` is irreflexive (e.g. NaN is unequal to 
itself).
I'm not sure that pointers to zero-sized variables make this significantly 
worse.
 

If we can at least agree that this ambiguity is no longer desirable,


I don't think we can agree on that, sorry.
 

let's consider the two possible definitions:

1. Pointers to distinct zero-size variables are equal:

This allows the compiler to easily optimize virtual address usage, but
is inconsistent with the non-zero-size definition.


Please look at the issue I filed for some discussion 

Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-27 Thread 'Axel Wagner' via golang-nuts
That would break backwards compatibility, though. And it would be a
re-definition (i.e. existing code would compile, but behave differently at
runtime) and is hence not allowed even under the Go 2 transition rules.
I'm also not sure you can exclude *all* pointers to zero-sized variables.
Note that `[0]T` is also zero-sized and you can convert slices (even empty
ones) into array-pointers. And you can take the address of struct fields.

All of this to solve an honestly pretty small issue. It's a corner, yes.
But it isn't a particularly sharp corner.

On Wed, Feb 28, 2024 at 8:06 AM 'Brian Candler' via golang-nuts <
golang-nuts@googlegroups.com> wrote:

> > let's consider the two possible definitions:
> >
> > 1. Pointers to distinct zero-size variables are equal: [...]
> > 2. Pointers to distinct zero-size variables are not equal:
>
> Another possibility:
>
> 3. Equality comparisons between pointers to zero-size variables are
> forbidden at compile time.
> 3a. If you wrap two such values in interfaces and try to compare them,
> then you get a runtime panic, same as certain cases today
> .
>
> Indeed, what if it were forbidden to take a pointer to a zero-sized
> variable in the first place? There is nothing to point at, after all.
>
> On Wednesday 28 February 2024 at 07:17:24 UTC+7 Brien Colwell wrote:
>
>> I think the surprising part is that the comparison result can change for
>> the same values because of the assumption that pointers never change. This
>> is implied by the spec but easy to miss.
>>
>> "Pointers to distinct zero-size variables may or may not be equal."
>> "Pointers to distinct zero-size variables may or may not be equal and the
>> results may or may not be repeatable in any context."
>>
>> Agree once a programmer is aware of the behavior it can be avoided.
>>
>> Best,
>> Brien
>>
>>
>> On Feb 27, 2024, at 3:06 PM, 'Axel Wagner' via golang-nuts <
>> golan...@googlegroups.com> wrote:
>>
>> On Tue, Feb 27, 2024 at 8:19 PM Marvin Renich  wrote:
>>
>>> Prior to generics, the type of the
>>> arguments to == were easily known to the programmer, and so it was
>>> obvious when this "undefined" exception would raise its ugly head, and
>>> you just didn't use it for empty struct types.  But now, with generics,
>>> this can only be classified as a glaring BUG in the spec.
>>
>>
>> There is pretty much a 0% chance that we'd change the spec in this
>> regard, at this point. It would mean that variable declarations like
>> `[1<<30]struct{}` would have to allocate huge chunks of heap, to ensure
>> that different index-expressions can have different addresses. And while
>> there shouldn't be any code relying on that not happening for correctness,
>> there is definitely code out there relying on it for performance (e.g.
>> there is a pattern of adding struct fields like `_ [0]func()` to ensure a
>> type is not comparable - such a struct would now change alignment and size).
>>
>> The optimization that variables of zero size can re-use the same address
>> has been in Go since before Go 1. Given this, it is pretty much implied
>> that comparison of those pointers will sometimes have weird results - the
>> only question is, *which* results are weird. I agree that this is one of
>> the weirder cases. But I don't think we can practically define `==` for
>> pointers to zero-sized variables.
>>
>> I'll also point out that for generics specifically, I'm not sure *any*
>> action would have a practical effect. If the type argument is not
>> statically known, we also can't special-case it to take into account that
>> it's a pointer to a zero-sized variable. Note that the triggered
>> optimization isn't necessarily "these are pointers to zero-sized variables,
>> hence I can do whatever I want" - it's "these are pointers to distinct
>> variables, hence I can assume they are unequal". That is a generally useful
>> optimization and it would still be applied to generic code.
>>
>> How can a programmer count on x == y having any meaning at all in code
>>> like this:
>>>
>>> func IsEqual[T comparable](x, y T) bool {
>>> return x == y
>>> }
>>>
>>> if the definition of == for empty structs is undefined?
>>
>>
>> The result is defined for empty structs, just not for *pointers* to empty
>> structs.
>> Note that `==` has other edge-cases as well. In particular, for floating
>> point/complex type arguments, `==` is irreflexive (e.g. NaN is unequal to
>> itself).
>> I'm not sure that pointers to zero-sized variables make this
>> significantly worse.
>>
>>
>>> If we can at least agree that this ambiguity is no longer desirable,
>>>
>>
>> I don't think we can agree on that, sorry.
>>
>>
>>> let's consider the two possible definitions:
>>>
>>> 1. Pointers to distinct zero-size variables are equal:
>>>
>>> This allows the compiler to easily optimize virtual address usage, but
>>> is inconsistent with the non-zero-size definition.
>>>
>>
>> Please look at the issue I filed for some discussion of 

Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-27 Thread 'Brian Candler' via golang-nuts
> let's consider the two possible definitions:
>
> 1. Pointers to distinct zero-size variables are equal: [...]
> 2. Pointers to distinct zero-size variables are not equal:

Another possibility:

3. Equality comparisons between pointers to zero-size variables are 
forbidden at compile time.
3a. If you wrap two such values in interfaces and try to compare them, then 
you get a runtime panic, same as certain cases today 
.

Indeed, what if it were forbidden to take a pointer to a zero-sized 
variable in the first place? There is nothing to point at, after all.

On Wednesday 28 February 2024 at 07:17:24 UTC+7 Brien Colwell wrote:

> I think the surprising part is that the comparison result can change for 
> the same values because of the assumption that pointers never change. This 
> is implied by the spec but easy to miss.
>
> "Pointers to distinct zero-size variables may or may not be equal."
> "Pointers to distinct zero-size variables may or may not be equal and the 
> results may or may not be repeatable in any context."
>
> Agree once a programmer is aware of the behavior it can be avoided.
>
> Best,
> Brien
>
>
> On Feb 27, 2024, at 3:06 PM, 'Axel Wagner' via golang-nuts <
> golan...@googlegroups.com> wrote:
>
> On Tue, Feb 27, 2024 at 8:19 PM Marvin Renich  wrote:
>
>> Prior to generics, the type of the
>> arguments to == were easily known to the programmer, and so it was
>> obvious when this "undefined" exception would raise its ugly head, and
>> you just didn't use it for empty struct types.  But now, with generics,
>> this can only be classified as a glaring BUG in the spec.
>
>
> There is pretty much a 0% chance that we'd change the spec in this regard, 
> at this point. It would mean that variable declarations like 
> `[1<<30]struct{}` would have to allocate huge chunks of heap, to ensure 
> that different index-expressions can have different addresses. And while 
> there shouldn't be any code relying on that not happening for correctness, 
> there is definitely code out there relying on it for performance (e.g. 
> there is a pattern of adding struct fields like `_ [0]func()` to ensure a 
> type is not comparable - such a struct would now change alignment and size).
>
> The optimization that variables of zero size can re-use the same address 
> has been in Go since before Go 1. Given this, it is pretty much implied 
> that comparison of those pointers will sometimes have weird results - the 
> only question is, *which* results are weird. I agree that this is one of 
> the weirder cases. But I don't think we can practically define `==` for 
> pointers to zero-sized variables.
>
> I'll also point out that for generics specifically, I'm not sure *any* 
> action would have a practical effect. If the type argument is not 
> statically known, we also can't special-case it to take into account that 
> it's a pointer to a zero-sized variable. Note that the triggered 
> optimization isn't necessarily "these are pointers to zero-sized variables, 
> hence I can do whatever I want" - it's "these are pointers to distinct 
> variables, hence I can assume they are unequal". That is a generally useful 
> optimization and it would still be applied to generic code.
>
> How can a programmer count on x == y having any meaning at all in code 
>> like this:
>>
>> func IsEqual[T comparable](x, y T) bool {
>> return x == y
>> }
>>
>> if the definition of == for empty structs is undefined?
>
>
> The result is defined for empty structs, just not for *pointers* to empty 
> structs.
> Note that `==` has other edge-cases as well. In particular, for floating 
> point/complex type arguments, `==` is irreflexive (e.g. NaN is unequal to 
> itself).
> I'm not sure that pointers to zero-sized variables make this significantly 
> worse.
>  
>
>> If we can at least agree that this ambiguity is no longer desirable,
>>
>
> I don't think we can agree on that, sorry.
>  
>
>> let's consider the two possible definitions:
>>
>> 1. Pointers to distinct zero-size variables are equal:
>>
>> This allows the compiler to easily optimize virtual address usage, but
>> is inconsistent with the non-zero-size definition.
>>
>
> Please look at the issue I filed for some discussion of edge-cases we are 
> unlikely to be able to cover satisfactorily. One obvious case is when 
> converting them to `unsafe.Pointer`, in which case the compiler no longer 
> knows that they point at zero-sized variables. Potentially, any such 
> conversion would have to re-assign them the magic "zero-sized variable" 
> address, which then would potentially lead to other weird comparison 
> implications, when code assumes that two `unsafe.Pointer` pointing at 
> distinct variables should have distinct addresses.
>
> We could probably make *more* such comparisons evaluate to `true`, but 
> it's unlikely that we could ever cover *all* of them. It would potentially 
> have prohibitive performance-impact on slicing operations, for example.

Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-27 Thread Brien Colwell
I think the surprising part is that the comparison result can change for the 
same values because of the assumption that pointers never change. This is 
implied by the spec but easy to miss.

"Pointers to distinct zero-size variables may or may not be equal."
"Pointers to distinct zero-size variables may or may not be equal and the 
results may or may not be repeatable in any context."

Agree once a programmer is aware of the behavior it can be avoided.

Best,
Brien


> On Feb 27, 2024, at 3:06 PM, 'Axel Wagner' via golang-nuts 
>  wrote:
> 
> On Tue, Feb 27, 2024 at 8:19 PM Marvin Renich  > wrote:
>> Prior to generics, the type of the
>> arguments to == were easily known to the programmer, and so it was
>> obvious when this "undefined" exception would raise its ugly head, and
>> you just didn't use it for empty struct types.  But now, with generics,
>> this can only be classified as a glaring BUG in the spec.
> 
> There is pretty much a 0% chance that we'd change the spec in this regard, at 
> this point. It would mean that variable declarations like `[1<<30]struct{}` 
> would have to allocate huge chunks of heap, to ensure that different 
> index-expressions can have different addresses. And while there shouldn't be 
> any code relying on that not happening for correctness, there is definitely 
> code out there relying on it for performance (e.g. there is a pattern of 
> adding struct fields like `_ [0]func()` to ensure a type is not comparable - 
> such a struct would now change alignment and size).
> 
> The optimization that variables of zero size can re-use the same address has 
> been in Go since before Go 1. Given this, it is pretty much implied that 
> comparison of those pointers will sometimes have weird results - the only 
> question is, *which* results are weird. I agree that this is one of the 
> weirder cases. But I don't think we can practically define `==` for pointers 
> to zero-sized variables.
> 
> I'll also point out that for generics specifically, I'm not sure *any* action 
> would have a practical effect. If the type argument is not statically known, 
> we also can't special-case it to take into account that it's a pointer to a 
> zero-sized variable. Note that the triggered optimization isn't necessarily 
> "these are pointers to zero-sized variables, hence I can do whatever I want" 
> - it's "these are pointers to distinct variables, hence I can assume they are 
> unequal". That is a generally useful optimization and it would still be 
> applied to generic code.
> 
>> How can a programmer count on x == y having any meaning at all in code like 
>> this:
>> 
>> func IsEqual[T comparable](x, y T) bool {
>> return x == y
>> }
>> 
>> if the definition of == for empty structs is undefined?
> 
> The result is defined for empty structs, just not for *pointers* to empty 
> structs.
> Note that `==` has other edge-cases as well. In particular, for floating 
> point/complex type arguments, `==` is irreflexive (e.g. NaN is unequal to 
> itself).
> I'm not sure that pointers to zero-sized variables make this significantly 
> worse.
>  
>> If we can at least agree that this ambiguity is no longer desirable,
> 
> I don't think we can agree on that, sorry.
>  
>> let's consider the two possible definitions:
>> 
>> 1. Pointers to distinct zero-size variables are equal:
>> 
>> This allows the compiler to easily optimize virtual address usage, but
>> is inconsistent with the non-zero-size definition.
> 
> Please look at the issue I filed for some discussion of edge-cases we are 
> unlikely to be able to cover satisfactorily. One obvious case is when 
> converting them to `unsafe.Pointer`, in which case the compiler no longer 
> knows that they point at zero-sized variables. Potentially, any such 
> conversion would have to re-assign them the magic "zero-sized variable" 
> address, which then would potentially lead to other weird comparison 
> implications, when code assumes that two `unsafe.Pointer` pointing at 
> distinct variables should have distinct addresses.
> 
> We could probably make *more* such comparisons evaluate to `true`, but it's 
> unlikely that we could ever cover *all* of them. It would potentially have 
> prohibitive performance-impact on slicing operations, for example.
> 
>> 2. Pointers to distinct zero-size variables are not equal:
>> 
>> This is consistent with the non-zero-size definition, but the
>> implementation would likely require distinct virtual addresses for
>> distinct variables.  Whether this would require committed memory
>> corresponding to those virtual addresses is unclear to me.
> 
> I believe it would. In effect, `struct{}` would have to take at least one 
> byte (as would a zero-sized array).
> 
>> 
>> Definition 1 removes the distinction between empty struct values and
>> empty struct instances, and the only way for the programmer to get that
>> distinction back is by using a non-empty struct.
>> 
>> On the other hand, definition 2 

Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-27 Thread 'Axel Wagner' via golang-nuts
On Tue, Feb 27, 2024 at 8:19 PM Marvin Renich  wrote:

> Prior to generics, the type of the
> arguments to == were easily known to the programmer, and so it was
> obvious when this "undefined" exception would raise its ugly head, and
> you just didn't use it for empty struct types.  But now, with generics,
> this can only be classified as a glaring BUG in the spec.


There is pretty much a 0% chance that we'd change the spec in this regard,
at this point. It would mean that variable declarations like
`[1<<30]struct{}` would have to allocate huge chunks of heap, to ensure
that different index-expressions can have different addresses. And while
there shouldn't be any code relying on that not happening for correctness,
there is definitely code out there relying on it for performance (e.g.
there is a pattern of adding struct fields like `_ [0]func()` to ensure a
type is not comparable - such a struct would now change alignment and size).

The optimization that variables of zero size can re-use the same address
has been in Go since before Go 1. Given this, it is pretty much implied
that comparison of those pointers will sometimes have weird results - the
only question is, *which* results are weird. I agree that this is one of
the weirder cases. But I don't think we can practically define `==` for
pointers to zero-sized variables.

I'll also point out that for generics specifically, I'm not sure *any*
action would have a practical effect. If the type argument is not
statically known, we also can't special-case it to take into account that
it's a pointer to a zero-sized variable. Note that the triggered
optimization isn't necessarily "these are pointers to zero-sized variables,
hence I can do whatever I want" - it's "these are pointers to distinct
variables, hence I can assume they are unequal". That is a generally useful
optimization and it would still be applied to generic code.

How can a programmer count on x == y having any meaning at all in code like
> this:
>
> func IsEqual[T comparable](x, y T) bool {
> return x == y
> }
>
> if the definition of == for empty structs is undefined?


The result is defined for empty structs, just not for *pointers* to empty
structs.
Note that `==` has other edge-cases as well. In particular, for floating
point/complex type arguments, `==` is irreflexive (e.g. NaN is unequal to
itself).
I'm not sure that pointers to zero-sized variables make this significantly
worse.


> If we can at least agree that this ambiguity is no longer desirable,
>

I don't think we can agree on that, sorry.


> let's consider the two possible definitions:
>
> 1. Pointers to distinct zero-size variables are equal:
>
> This allows the compiler to easily optimize virtual address usage, but
> is inconsistent with the non-zero-size definition.
>

Please look at the issue I filed for some discussion of edge-cases we are
unlikely to be able to cover satisfactorily. One obvious case is when
converting them to `unsafe.Pointer`, in which case the compiler no longer
knows that they point at zero-sized variables. Potentially, any such
conversion would have to re-assign them the magic "zero-sized variable"
address, which then would potentially lead to other weird comparison
implications, when code assumes that two `unsafe.Pointer` pointing at
distinct variables should have distinct addresses.

We could probably make *more* such comparisons evaluate to `true`, but it's
unlikely that we could ever cover *all* of them. It would potentially have
prohibitive performance-impact on slicing operations, for example.

2. Pointers to distinct zero-size variables are not equal:
>
> This is consistent with the non-zero-size definition, but the
> implementation would likely require distinct virtual addresses for
> distinct variables.  Whether this would require committed memory
> corresponding to those virtual addresses is unclear to me.
>

I believe it would. In effect, `struct{}` would have to take at least one
byte (as would a zero-sized array).


> Definition 1 removes the distinction between empty struct values and
> empty struct instances, and the only way for the programmer to get that
> distinction back is by using a non-empty struct.
>
> On the other hand, definition 2 preserves the distinction.  If a
> programmer wants to have instances compare as equal, it is often very
> easy to use instances of the empty type rather than instances of a
> pointer to the empty type.  Implement the methods on the type with value
> receivers rather than pointer receivers.
>

I think if these arguments hold any water, the argument "the programmer
just shouldn't use pointers to zero-sized variables, if they want defined
semantics for ==" is just as valid. That is, if they have control over the
type and we are willing to force them to make a decision aligning with our
definition, why not force them to make a decision aligning with there not
being a definition?


>
> ...Marvin
>
> --
> You received this message because you are 

Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-27 Thread Marvin Renich
* Kurtis Rader  [240227 03:10]:
> On Mon, Feb 26, 2024 at 11:52 PM tapi...@gmail.com 
> wrote:
> 
> > On Tuesday, February 27, 2024 at 3:42:25 PM UTC+8 Jan Mercl wrote:
> >
> > On Tue, Feb 27, 2024 at 6:20 AM tapi...@gmail.com 
> > wrote:
> >
> > > From common sense, this is an obvious bug. But the spec is indeed not
> > clear enough.
> > > It doesn't state whether or not comparisons of pointers to two distinct
> > zero-size variables should be consistent in a run session.
> > > Though, from common sense, it should.
> >
> > "Pointers to distinct zero-size variables may or may not be equal."
> >
> > The outcome is specified to be not predictable. Expecting consistency
> > means the outcome should be, or eventually become, predictable. That's
> > the opposite of what the specs say.
> >
> >
> > Then I would argue that the spec never guarantee (x != y) == ! (x == y).
> > for values of any types (including non-zero-size types). :D
> >
> 
> The spec is reasonably clear that guarantee does apply to pointers to
> non-zero size variables (e.g., non-empty structs). The issue in this
> discussion thread is limited to the handling of pointers to zero size
> variables.

I interpreted this thread as being about the inconsistency between the
way pointers to zero-size variables were compared vs. non-zero-size
variables.  His comment looks perfectly on-topic to me.

> Precisely because of optimizations the compiler may, or may not,
> perform regarding the value of such pointers. I would prefer a stronger
> guarantee regarding pointers to zero size variables, and it looks like a
> lot of Go users agree with you and me, but that doesn't mean the current
> behavior is ipso facto broken or useless. Pointers to zero size variables
> (e.g., empty structs) are a special-case that the Go designers decided to
> leave ambiguous for now.

I have to agree with tapir.  Prior to generics, the type of the
arguments to == were easily known to the programmer, and so it was
obvious when this "undefined" exception would raise its ugly head, and
you just didn't use it for empty struct types.  But now, with generics,
this can only be classified as a glaring BUG in the spec.  How can a
programmer count on x == y having any meaning at all in code like this:

func IsEqual[T comparable](x, y T) bool {
return x == y
}

if the definition of == for empty structs is undefined?  And especially
if the result is different depending on whether or not code outside this
function has called  for z passed as an argument?
https://gotipplay.golang.org/p/ymhsDmJWv8l

If we can at least agree that this ambiguity is no longer desirable,
let's consider the two possible definitions:

1. Pointers to distinct zero-size variables are equal:

This allows the compiler to easily optimize virtual address usage, but
is inconsistent with the non-zero-size definition.

2. Pointers to distinct zero-size variables are not equal:

This is consistent with the non-zero-size definition, but the
implementation would likely require distinct virtual addresses for
distinct variables.  Whether this would require committed memory
corresponding to those virtual addresses is unclear to me.

Definition 1 removes the distinction between empty struct values and
empty struct instances, and the only way for the programmer to get that
distinction back is by using a non-empty struct.

On the other hand, definition 2 preserves the distinction.  If a
programmer wants to have instances compare as equal, it is often very
easy to use instances of the empty type rather than instances of a
pointer to the empty type.  Implement the methods on the type with value
receivers rather than pointer receivers.

...Marvin

-- 
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/Zd41i3rHLskqBuef%40basil.wdw.


Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-27 Thread Kurtis Rader
On Mon, Feb 26, 2024 at 11:52 PM tapi...@gmail.com 
wrote:

> On Tuesday, February 27, 2024 at 3:42:25 PM UTC+8 Jan Mercl wrote:
>
> On Tue, Feb 27, 2024 at 6:20 AM tapi...@gmail.com 
> wrote:
>
> > From common sense, this is an obvious bug. But the spec is indeed not
> clear enough.
> > It doesn't state whether or not comparisons of pointers to two distinct
> zero-size variables should be consistent in a run session.
> > Though, from common sense, it should.
>
> "Pointers to distinct zero-size variables may or may not be equal."
>
> The outcome is specified to be not predictable. Expecting consistency
> means the outcome should be, or eventually become, predictable. That's
> the opposite of what the specs say.
>
>
> Then I would argue that the spec never guarantee (x != y) == ! (x == y).
> for values of any types (including non-zero-size types). :D
>

The spec is reasonably clear that guarantee does apply to pointers to
non-zero size variables (e.g., non-empty structs). The issue in this
discussion thread is limited to the handling of pointers to zero size
variables. Precisely because of optimizations the compiler may, or may not,
perform regarding the value of such pointers. I would prefer a stronger
guarantee regarding pointers to zero size variables, and it looks like a
lot of Go users agree with you and me, but that doesn't mean the current
behavior is ipso facto broken or useless. Pointers to zero size variables
(e.g., empty structs) are a special-case that the Go designers decided to
leave ambiguous for now.

-- 
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/CABx2%3DD_dBchTJ0LWbRH6j-LLaFz4SBBnwbo_9qFEO4GFfv7asw%40mail.gmail.com.


Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-26 Thread tapi...@gmail.com


On Tuesday, February 27, 2024 at 3:42:25 PM UTC+8 Jan Mercl wrote:

On Tue, Feb 27, 2024 at 6:20 AM tapi...@gmail.com  
wrote: 

> From common sense, this is an obvious bug. But the spec is indeed not 
clear enough. 
> It doesn't state whether or not comparisons of pointers to two distinct 
zero-size variables should be consistent in a run session. 
> Though, from common sense, it should. 

"Pointers to distinct zero-size variables may or may not be equal." 

The outcome is specified to be not predictable. Expecting consistency 
means the outcome should be, or eventually become, predictable. That's 
the opposite of what the specs say. 


Then I would argue that the spec never guarantee (x != y) == ! (x == y).
for values of any types (including non-zero-size types). :D

-- 
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/4972f679-062b-4a4c-bf8e-31ab59d0147fn%40googlegroups.com.


Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-26 Thread Jan Mercl
On Tue, Feb 27, 2024 at 6:20 AM tapi...@gmail.com  wrote:

> From common sense, this is an obvious bug. But the spec is indeed not clear 
> enough.
> It doesn't state whether or not comparisons of pointers to two distinct 
> zero-size variables should be consistent in a run session.
> Though, from common sense, it should.

"Pointers to distinct zero-size variables may or may not be equal."

The outcome is specified to be not predictable. Expecting consistency
means the outcome should be, or eventually become, predictable. That's
the opposite of what the specs say.

-- 
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/CAA40n-XN-U8JrVJ0uJqbftk2fNSiHEoDu7qsOde-FwHc5voSVg%40mail.gmail.com.


Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-26 Thread tapi...@gmail.com


On Tuesday, February 27, 2024 at 2:25:46 AM UTC+8 Brien Colwell wrote:

Interesting. That seems to break the comparable spec.

>> Pointer types are comparable. Two pointer values are equal if they point 
to the same variable or if both have value nil. Pointers to distinct 
zero-size variables may or may not be equal.


>From common sense, this is an obvious bug. But the spec is indeed not clear 
enough.
It doesn't state whether or not comparisons of pointers to two distinct 
zero-size variables should be consistent in a run session.
Though, from common sense, it should.
 


>> it would be valid for `==` on pointers to zero-sized types to always 
evaluate to `true`,

This would be more straightforward behavior.



On Feb 26, 2024, at 9:24 AM, tapi...@gmail.com  wrote:

package main

var a, b [0]int
var p, q = , 

func main() {
if (p == q) {
p, q = , 
println(p == q) // false
}
}

On Thursday, February 22, 2024 at 6:55:49 PM UTC+8 Brien Colwell wrote:

I'm confused by this output. It appears that the interface of two different 
pointers to an empty struct are equal. In all other cases, interface 
equality seems to be the pointer equality. What's going on in the empty 
struct case?

```
package main

import "fmt"

type Foo struct {
}

func (self *Foo) Hello() {
}

type FooWithValue struct {
A int
}

func (self *FooWithValue) Hello() {
}

type Bar interface {
Hello()
}

func main() {
a := {}
b := {}
fmt.Printf("%t\n", *a == *b)
fmt.Printf("%t\n", a == b)
fmt.Printf("%t\n", Bar(a) == Bar(b))

c := {A: 1}
d := {A: 1}
fmt.Printf("%t\n", *c == *d)
fmt.Printf("%t\n", c == d)
fmt.Printf("%t\n", Bar(c) == Bar(d))
}
```

Prints (emphasis added on the strange case):

```
true
false
**true**
true
false
false
```



-- 
You received this message because you are subscribed to a topic in the 
Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit 
https://groups.google.com/d/topic/golang-nuts/JBVqWYFdtC4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to 
golang-nuts...@googlegroups.com.

To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/6fc9b600-6707-414c-b19b-e5e14919c5a5n%40googlegroups.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/bf153de9-91fd-47e3-8aa3-b738a5b55109n%40googlegroups.com.


Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-26 Thread Brien Colwell
>> Note that there are two distinct variables involved (a and b).

You’re right. I misread this.


> On Feb 26, 2024, at 1:15 PM, Axel Wagner  
> wrote:
> 
> On Mon, Feb 26, 2024 at 7:25 PM Brien Colwell  > wrote:
>> Interesting. That seems to break the comparable spec.
>> 
>> >> Pointer types are comparable. Two pointer values are equal if they point 
>> >> to the same variable or if both have value nil. Pointers to distinct 
>> >> zero-size variables may or may not be equal.
> 
> How do you think this is broken? Note that there are two distinct variables 
> involved (a and b). Pointers to distinct variables are allowed to be equal, 
> or not to be equal.
>  
>> >> it would be valid for `==` on pointers to zero-sized types to always 
>> >> evaluate to `true`,
>> 
>> This would be more straightforward behavior.
>> 
>> 
>> 
>>> On Feb 26, 2024, at 9:24 AM, tapi...@gmail.com  
>>> mailto:tapir@gmail.com>> wrote:
>>> 
>>> package main
>>> 
>>> var a, b [0]int
>>> var p, q = , 
>>> 
>>> func main() {
>>> if (p == q) {
>>> p, q = , 
>>> println(p == q) // false
>>> }
>>> }
>>> 
>>> On Thursday, February 22, 2024 at 6:55:49 PM UTC+8 Brien Colwell wrote:
 I'm confused by this output. It appears that the interface of two 
 different pointers to an empty struct are equal. In all other cases, 
 interface equality seems to be the pointer equality. What's going on in 
 the empty struct case?
 
 ```
 package main
 
 import "fmt"
 
 type Foo struct {
 }
 
 func (self *Foo) Hello() {
 }
 
 type FooWithValue struct {
A int
 }
 
 func (self *FooWithValue) Hello() {
 }
 
 type Bar interface {
Hello()
 }
 
 func main() {
a := {}
b := {}
fmt.Printf("%t\n", *a == *b)
fmt.Printf("%t\n", a == b)
fmt.Printf("%t\n", Bar(a) == Bar(b))
 
c := {A: 1}
d := {A: 1}
fmt.Printf("%t\n", *c == *d)
fmt.Printf("%t\n", c == d)
fmt.Printf("%t\n", Bar(c) == Bar(d))
 }
 ```
 
 Prints (emphasis added on the strange case):
 
 ```
 true
 false
 **true**
 true
 false
 false
 ```
 
 
>>> 
>>> 
>>> -- 
>>> You received this message because you are subscribed to a topic in the 
>>> Google Groups "golang-nuts" group.
>>> To unsubscribe from this topic, visit 
>>> https://groups.google.com/d/topic/golang-nuts/JBVqWYFdtC4/unsubscribe.
>>> To unsubscribe from this group and all its topics, 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/6fc9b600-6707-414c-b19b-e5e14919c5a5n%40googlegroups.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/E875D5D3-FFB2-40BA-B930-A10461A2998E%40gmail.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/BF01D7A5-36A9-48A7-B35A-E18C81CF4A1E%40gmail.com.


Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-26 Thread 'Axel Wagner' via golang-nuts
On Mon, Feb 26, 2024 at 7:25 PM Brien Colwell  wrote:

> Interesting. That seems to break the comparable spec.
>
> >> Pointer types are comparable. Two pointer values are equal if they
> point to the same variable or if both have value nil. Pointers to distinct
> zero-size variables may or may not be equal.
>

How do you think this is broken? Note that there are two distinct variables
involved (a and b). Pointers to distinct variables are allowed to be equal,
or not to be equal.


> >> it would be valid for `==` on pointers to zero-sized types to always
> evaluate to `true`,
>
> This would be more straightforward behavior.
>
>
>
> On Feb 26, 2024, at 9:24 AM, tapi...@gmail.com 
> wrote:
>
> package main
>
> var a, b [0]int
> var p, q = , 
>
> func main() {
> if (p == q) {
> p, q = , 
> println(p == q) // false
> }
> }
>
> On Thursday, February 22, 2024 at 6:55:49 PM UTC+8 Brien Colwell wrote:
>
>> I'm confused by this output. It appears that the interface of two
>> different pointers to an empty struct are equal. In all other cases,
>> interface equality seems to be the pointer equality. What's going on in the
>> empty struct case?
>>
>> ```
>> package main
>>
>> import "fmt"
>>
>> type Foo struct {
>> }
>>
>> func (self *Foo) Hello() {
>> }
>>
>> type FooWithValue struct {
>> A int
>> }
>>
>> func (self *FooWithValue) Hello() {
>> }
>>
>> type Bar interface {
>> Hello()
>> }
>>
>> func main() {
>> a := {}
>> b := {}
>> fmt.Printf("%t\n", *a == *b)
>> fmt.Printf("%t\n", a == b)
>> fmt.Printf("%t\n", Bar(a) == Bar(b))
>>
>> c := {A: 1}
>> d := {A: 1}
>> fmt.Printf("%t\n", *c == *d)
>> fmt.Printf("%t\n", c == d)
>> fmt.Printf("%t\n", Bar(c) == Bar(d))
>> }
>> ```
>>
>> Prints (emphasis added on the strange case):
>>
>> ```
>> true
>> false
>> **true**
>> true
>> false
>> false
>> ```
>>
>>
>>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "golang-nuts" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/golang-nuts/JBVqWYFdtC4/unsubscribe.
> To unsubscribe from this group and all its topics, 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/6fc9b600-6707-414c-b19b-e5e14919c5a5n%40googlegroups.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/E875D5D3-FFB2-40BA-B930-A10461A2998E%40gmail.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/CAEkBMfG9WhdUFFxpFR0VhNa0tOG7xi01KuGuCmHkv4o3VfQ-zQ%40mail.gmail.com.


Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-26 Thread Brien Colwell
Interesting. That seems to break the comparable spec.

>> Pointer types are comparable. Two pointer values are equal if they point to 
>> the same variable or if both have value nil. Pointers to distinct zero-size 
>> variables may or may not be equal.


>> it would be valid for `==` on pointers to zero-sized types to always 
>> evaluate to `true`,

This would be more straightforward behavior.



> On Feb 26, 2024, at 9:24 AM, tapi...@gmail.com  wrote:
> 
> package main
> 
> var a, b [0]int
> var p, q = , 
> 
> func main() {
>   if (p == q) {
>   p, q = , 
>   println(p == q) // false
>   }
> }
> 
> On Thursday, February 22, 2024 at 6:55:49 PM UTC+8 Brien Colwell wrote:
>> I'm confused by this output. It appears that the interface of two different 
>> pointers to an empty struct are equal. In all other cases, interface 
>> equality seems to be the pointer equality. What's going on in the empty 
>> struct case?
>> 
>> ```
>> package main
>> 
>> import "fmt"
>> 
>> type Foo struct {
>> }
>> 
>> func (self *Foo) Hello() {
>> }
>> 
>> type FooWithValue struct {
>>  A int
>> }
>> 
>> func (self *FooWithValue) Hello() {
>> }
>> 
>> type Bar interface {
>>  Hello()
>> }
>> 
>> func main() {
>>  a := {}
>>  b := {}
>>  fmt.Printf("%t\n", *a == *b)
>>  fmt.Printf("%t\n", a == b)
>>  fmt.Printf("%t\n", Bar(a) == Bar(b))
>> 
>>  c := {A: 1}
>>  d := {A: 1}
>>  fmt.Printf("%t\n", *c == *d)
>>  fmt.Printf("%t\n", c == d)
>>  fmt.Printf("%t\n", Bar(c) == Bar(d))
>> }
>> ```
>> 
>> Prints (emphasis added on the strange case):
>> 
>> ```
>> true
>> false
>> **true**
>> true
>> false
>> false
>> ```
>> 
>> 
> 
> 
> -- 
> You received this message because you are subscribed to a topic in the Google 
> Groups "golang-nuts" group.
> To unsubscribe from this topic, visit 
> https://groups.google.com/d/topic/golang-nuts/JBVqWYFdtC4/unsubscribe.
> To unsubscribe from this group and all its topics, 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/6fc9b600-6707-414c-b19b-e5e14919c5a5n%40googlegroups.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/E875D5D3-FFB2-40BA-B930-A10461A2998E%40gmail.com.


Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-24 Thread 'Axel Wagner' via golang-nuts
FWIW I believe there is enough subtlety here (small changes in the code
might trigger different compiler optimizations) that I wouldn't rely too
much on probing the compiler with different programs. Instead, I'd suggest
decompiling the binary and/or running it in a debugger, to check what the
actual pointers are. From looking at godbolt, AIUI the compiler is
optimizing the comparison into a constant:
https://go.godbolt.org/z/x1Ef3PxPb

Though, really, I don't think this is *super* weird. Like, don't get me
wrong, the behavior is counter-intuitive. But once you've accepted that
"comparison of pointers to zero-sized variables is not really defined", the
actual myriads of ways in which it behaves counter-intuitively become less
important.



On Sat, Feb 24, 2024 at 5:28 PM jake...@gmail.com 
wrote:

> What is really fantastical is that a==b prints false, even though the
> pointers are actually the same. I am guessing some sort of optimization
> effect is at play here.
>
> https://go.dev/play/p/Dsqeh_aAXKT
>
> type Foo struct {
> }
>
> func main() {
>
> a := {}
> b := {}
> fmt.Printf("%t\n", *a == *b)
> fmt.Printf("%t\n", a == b)
> q := uintptr(unsafe.Pointer(a))
> r := uintptr(unsafe.Pointer(b))
> //fmt.Printf("%p %p\n", a, b)
> fmt.Printf("%t\n", q == r)
> fmt.Printf("%x %x\n", q, r)
> }
>
> prints:
>
> true
> false
> true
> c000104ee0 c000104ee0
>
> wild! (or am I missing something?)
> On Thursday, February 22, 2024 at 1:07:08 PM UTC-5 Axel Wagner wrote:
>
>> On Thu, Feb 22, 2024 at 6:44 PM burak serdar  wrote:
>>
>>> Maybe the spec should be clarified to say "for a compilation of a
>>> program, two pointers to zero-size variables may or may not be equal",
>>> because otherwise it implies that if you have
>>>
>>> x:= a==b
>>> y:= a==b
>>>
>>> x may or may not be true.
>>
>>
>> Well, given that the spec is *not* saying what you say it maybe should -
>> it seems we are in agreement. It is indeed correct for `x` to may or not be
>> equal to `y` here, with the spec as it is right now.
>>
>>
>>> If a==b, then that should hold for every
>>> execution of that program, and throughout the program.
>>>
>>>
>>> >
>>> >>
>>> >> That is, if a==b, then
>>> >> interface{}(a)==interface{}(b), and vice versa. But what we have here
>>> >> is a!=b but interface{}(a)==interface{}(b)
>>> >>
>>> >> On Thu, Feb 22, 2024 at 9:50 AM Axel Wagner
>>> >>  wrote:
>>> >> >
>>> >> > Hm actually, the spec allows for this, technically speaking:
>>> https://go.dev/ref/spec#Comparison_operators
>>> >> >
>>> >> > > Pointers to distinct zero-size variables may or may not be equal.
>>> >> >
>>> >> > Arguably, this genuinely would allow comparison of pointers to
>>> zero-sized variables to have any behavior whatsoever (including being
>>> random). But it certainly is confusing.
>>> >> >
>>> >> >
>>> >> > On Thu, Feb 22, 2024 at 5:46 PM Axel Wagner <
>>> axel.wa...@googlemail.com> wrote:
>>> >> >>
>>> >> >> I see. Sorry, I was jumping to conclusions and didn't quite get
>>> what you mean. That is my fault.
>>> >> >>
>>> >> >> I agree that this looks confusing and is arguably a bug. I filed
>>> https://github.com/golang/go/issues/65878, thanks for pointing it out.
>>> >> >>
>>> >> >> On Thu, Feb 22, 2024 at 5:20 PM burak serdar 
>>> wrote:
>>> >> >>>
>>> >> >>> Creating  an interface is not creating a pointer to a zero sized
>>> variable.
>>> >> >>>
>>> >> >>> a==b  prints false. That means, a and b point to different
>>> locations
>>> >> >>> Bar(a)==Bar(b) prints true. If a!=b, then Bar(a) must be
>>> different from Bar(b)
>>> >> >>>
>>> >> >>> On Thu, Feb 22, 2024 at 9:15 AM Axel Wagner
>>> >> >>>  wrote:
>>> >> >>> >
>>> >> >>> > If you expect that, you are misreading the spec. There is no
>>> guarantee of any behavior here. An implementation is allowed to flip a
>>> coin, every time you create a pointer to a zero-sized variable, and either
>>> return a unique pointer or a singleton. I think you may assume that  ==
>>> , always. But apart from that, who knows.
>>> >> >>> >
>>> >> >>> > Zero-sized variables *may* have the same address. They don't
>>> *have* to.
>>> >> >>> >
>>> >> >>> > On Thu, Feb 22, 2024 at 5:12 PM burak serdar <
>>> bse...@computer.org> wrote:
>>> >> >>> >>
>>> >> >>> >> On Thu, Feb 22, 2024 at 9:00 AM Axel Wagner
>>> >> >>> >>  wrote:
>>> >> >>> >> >
>>> >> >>> >> > Note that in the Spec section I quoted above it says "Two
>>> distinct zero-size variables may have the same address in memory" (emphasis
>>> mine).
>>> >> >>> >> > There is no guarantee, that all zero-sized values have the
>>> same address (otherwise, you'd get into inefficiencies when taking the
>>> address of a zero-sized field in a larger struct, or when converting a
>>> zero-capacity slice into an array-pointer). But it is allowed.
>>> >> >>> >> > If you require two pointers returned from different code
>>> paths to be different, for correctness, then you have to make them point at
>>> something that has non-zero size. Otherwise, all potential combinations 

Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-24 Thread jake...@gmail.com
What is really fantastical is that a==b prints false, even though the 
pointers are actually the same. I am guessing some sort of optimization 
effect is at play here. 

https://go.dev/play/p/Dsqeh_aAXKT

type Foo struct {
}

func main() {

a := {}
b := {}
fmt.Printf("%t\n", *a == *b)
fmt.Printf("%t\n", a == b)
q := uintptr(unsafe.Pointer(a))
r := uintptr(unsafe.Pointer(b))
//fmt.Printf("%p %p\n", a, b)
fmt.Printf("%t\n", q == r)
fmt.Printf("%x %x\n", q, r)
} 

prints:

true 
false 
true 
c000104ee0 c000104ee0

wild! (or am I missing something?)
On Thursday, February 22, 2024 at 1:07:08 PM UTC-5 Axel Wagner wrote:

> On Thu, Feb 22, 2024 at 6:44 PM burak serdar  wrote:
>
>> Maybe the spec should be clarified to say "for a compilation of a
>> program, two pointers to zero-size variables may or may not be equal",
>> because otherwise it implies that if you have
>>
>> x:= a==b
>> y:= a==b
>>
>> x may or may not be true.
>
>
> Well, given that the spec is *not* saying what you say it maybe should - 
> it seems we are in agreement. It is indeed correct for `x` to may or not be 
> equal to `y` here, with the spec as it is right now.
>  
>
>> If a==b, then that should hold for every
>> execution of that program, and throughout the program.
>>
>>
>> >
>> >>
>> >> That is, if a==b, then
>> >> interface{}(a)==interface{}(b), and vice versa. But what we have here
>> >> is a!=b but interface{}(a)==interface{}(b)
>> >>
>> >> On Thu, Feb 22, 2024 at 9:50 AM Axel Wagner
>> >>  wrote:
>> >> >
>> >> > Hm actually, the spec allows for this, technically speaking: 
>> https://go.dev/ref/spec#Comparison_operators
>> >> >
>> >> > > Pointers to distinct zero-size variables may or may not be equal.
>> >> >
>> >> > Arguably, this genuinely would allow comparison of pointers to 
>> zero-sized variables to have any behavior whatsoever (including being 
>> random). But it certainly is confusing.
>> >> >
>> >> >
>> >> > On Thu, Feb 22, 2024 at 5:46 PM Axel Wagner <
>> axel.wa...@googlemail.com> wrote:
>> >> >>
>> >> >> I see. Sorry, I was jumping to conclusions and didn't quite get 
>> what you mean. That is my fault.
>> >> >>
>> >> >> I agree that this looks confusing and is arguably a bug. I filed 
>> https://github.com/golang/go/issues/65878, thanks for pointing it out.
>> >> >>
>> >> >> On Thu, Feb 22, 2024 at 5:20 PM burak serdar  
>> wrote:
>> >> >>>
>> >> >>> Creating  an interface is not creating a pointer to a zero sized 
>> variable.
>> >> >>>
>> >> >>> a==b  prints false. That means, a and b point to different 
>> locations
>> >> >>> Bar(a)==Bar(b) prints true. If a!=b, then Bar(a) must be different 
>> from Bar(b)
>> >> >>>
>> >> >>> On Thu, Feb 22, 2024 at 9:15 AM Axel Wagner
>> >> >>>  wrote:
>> >> >>> >
>> >> >>> > If you expect that, you are misreading the spec. There is no 
>> guarantee of any behavior here. An implementation is allowed to flip a 
>> coin, every time you create a pointer to a zero-sized variable, and either 
>> return a unique pointer or a singleton. I think you may assume that  == 
>> , always. But apart from that, who knows.
>> >> >>> >
>> >> >>> > Zero-sized variables *may* have the same address. They don't 
>> *have* to.
>> >> >>> >
>> >> >>> > On Thu, Feb 22, 2024 at 5:12 PM burak serdar <
>> bse...@computer.org> wrote:
>> >> >>> >>
>> >> >>> >> On Thu, Feb 22, 2024 at 9:00 AM Axel Wagner
>> >> >>> >>  wrote:
>> >> >>> >> >
>> >> >>> >> > Note that in the Spec section I quoted above it says "Two 
>> distinct zero-size variables may have the same address in memory" (emphasis 
>> mine).
>> >> >>> >> > There is no guarantee, that all zero-sized values have the 
>> same address (otherwise, you'd get into inefficiencies when taking the 
>> address of a zero-sized field in a larger struct, or when converting a 
>> zero-capacity slice into an array-pointer). But it is allowed.
>> >> >>> >> > If you require two pointers returned from different code 
>> paths to be different, for correctness, then you have to make them point at 
>> something that has non-zero size. Otherwise, all potential combinations are 
>> valid according to the spec.
>> >> >>> >>
>> >> >>> >> Yes. But in that case, you'd expect either  a==b and 
>> Bar(a)==Bar(b) to
>> >> >>> >> be both true, or both false. In this case, one is true and the 
>> other
>> >> >>> >> is not.
>> >> >>> >>
>> >> >>> >>
>> >> >>> >> >
>> >> >>> >> > On Thu, Feb 22, 2024 at 4:53 PM burak serdar <
>> bse...@computer.org> wrote:
>> >> >>> >> >>
>> >> >>> >> >> The compiler can allocate the same address for empty 
>> structs, so I
>> >> >>> >> >> actually expected a==b to be true, not false. However, 
>> there's
>> >> >>> >> >> something more interesting going on here because:
>> >> >>> >> >>
>> >> >>> >> >> a := {}
>> >> >>> >> >> b := {}
>> >> >>> >> >> fmt.Printf("%t\n", *a == *b)
>> >> >>> >> >> fmt.Printf("%t\n", a == b)
>> >> >>> >> >> fmt.Printf("%p %p\n", a, b)
>> >> >>> >> >> x := Bar(a)
>> >> >>> >> >> y := Bar(b)
>> >> >>> >> >> fmt.Printf("%t\n", 

Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-22 Thread burak serdar
On Thu, Feb 22, 2024 at 10:39 AM Axel Wagner
 wrote:
>
>
>
> On Thu, Feb 22, 2024 at 6:06 PM burak serdar  wrote:
>>
>> I don't think this case really applies here. I get that comparison of
>> a==b may or may not be true. The problem is that if a==b at some point
>> in a program, it should be the case that a==b for all other cases in
>> that same program.
>
>
> Why? I mean, I get that it makes sense intuitively, but how does this follow 
> from the spec? That sentence says "a comparison of two pointers to zero sized 
> values may or may not be true". It does not qualify that statement in any way.

We are comparing two interfaces containing pointers to zero-size
structs. If those pointers are not equal, then the interfaces should
not be equal as well.

Maybe the spec should be clarified to say "for a compilation of a
program, two pointers to zero-size variables may or may not be equal",
because otherwise it implies that if you have

x:= a==b
y:= a==b

x may or may not be true. If a==b, then that should hold for every
execution of that program, and throughout the program.


>
>>
>> That is, if a==b, then
>> interface{}(a)==interface{}(b), and vice versa. But what we have here
>> is a!=b but interface{}(a)==interface{}(b)
>>
>> On Thu, Feb 22, 2024 at 9:50 AM Axel Wagner
>>  wrote:
>> >
>> > Hm actually, the spec allows for this, technically speaking: 
>> > https://go.dev/ref/spec#Comparison_operators
>> >
>> > > Pointers to distinct zero-size variables may or may not be equal.
>> >
>> > Arguably, this genuinely would allow comparison of pointers to zero-sized 
>> > variables to have any behavior whatsoever (including being random). But it 
>> > certainly is confusing.
>> >
>> >
>> > On Thu, Feb 22, 2024 at 5:46 PM Axel Wagner 
>> >  wrote:
>> >>
>> >> I see. Sorry, I was jumping to conclusions and didn't quite get what you 
>> >> mean. That is my fault.
>> >>
>> >> I agree that this looks confusing and is arguably a bug. I filed 
>> >> https://github.com/golang/go/issues/65878, thanks for pointing it out.
>> >>
>> >> On Thu, Feb 22, 2024 at 5:20 PM burak serdar  wrote:
>> >>>
>> >>> Creating  an interface is not creating a pointer to a zero sized 
>> >>> variable.
>> >>>
>> >>> a==b  prints false. That means, a and b point to different locations
>> >>> Bar(a)==Bar(b) prints true. If a!=b, then Bar(a) must be different from 
>> >>> Bar(b)
>> >>>
>> >>> On Thu, Feb 22, 2024 at 9:15 AM Axel Wagner
>> >>>  wrote:
>> >>> >
>> >>> > If you expect that, you are misreading the spec. There is no guarantee 
>> >>> > of any behavior here. An implementation is allowed to flip a coin, 
>> >>> > every time you create a pointer to a zero-sized variable, and either 
>> >>> > return a unique pointer or a singleton. I think you may assume that  
>> >>> > == , always. But apart from that, who knows.
>> >>> >
>> >>> > Zero-sized variables *may* have the same address. They don't *have* to.
>> >>> >
>> >>> > On Thu, Feb 22, 2024 at 5:12 PM burak serdar  
>> >>> > wrote:
>> >>> >>
>> >>> >> On Thu, Feb 22, 2024 at 9:00 AM Axel Wagner
>> >>> >>  wrote:
>> >>> >> >
>> >>> >> > Note that in the Spec section I quoted above it says "Two distinct 
>> >>> >> > zero-size variables may have the same address in memory" (emphasis 
>> >>> >> > mine).
>> >>> >> > There is no guarantee, that all zero-sized values have the same 
>> >>> >> > address (otherwise, you'd get into inefficiencies when taking the 
>> >>> >> > address of a zero-sized field in a larger struct, or when 
>> >>> >> > converting a zero-capacity slice into an array-pointer). But it is 
>> >>> >> > allowed.
>> >>> >> > If you require two pointers returned from different code paths to 
>> >>> >> > be different, for correctness, then you have to make them point at 
>> >>> >> > something that has non-zero size. Otherwise, all potential 
>> >>> >> > combinations are valid according to the spec.
>> >>> >>
>> >>> >> Yes. But in that case, you'd expect either  a==b and Bar(a)==Bar(b) to
>> >>> >> be both true, or both false. In this case, one is true and the other
>> >>> >> is not.
>> >>> >>
>> >>> >>
>> >>> >> >
>> >>> >> > On Thu, Feb 22, 2024 at 4:53 PM burak serdar  
>> >>> >> > wrote:
>> >>> >> >>
>> >>> >> >> The compiler can allocate the same address for empty structs, so I
>> >>> >> >> actually expected a==b to be true, not false. However, there's
>> >>> >> >> something more interesting going on here because:
>> >>> >> >>
>> >>> >> >> a := {}
>> >>> >> >> b := {}
>> >>> >> >> fmt.Printf("%t\n", *a == *b)
>> >>> >> >> fmt.Printf("%t\n", a == b)
>> >>> >> >> fmt.Printf("%p %p\n", a, b)
>> >>> >> >> x := Bar(a)
>> >>> >> >> y := Bar(b)
>> >>> >> >> fmt.Printf("%t\n", Bar(a) == Bar(b))
>> >>> >> >> fmt.Printf("%t\n", x == y)
>> >>> >> >>
>> >>> >> >> Prints:
>> >>> >> >>
>> >>> >> >> true
>> >>> >> >> true
>> >>> >> >> 0x58e360 0x58e360 // Note that a and be are pointing to the same 
>> >>> >> >> address
>> >>> >> >> true
>> >>> >> >> true
>> >>> >> >>
>> >>> >> >>
>> >>> >> >> 

Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-22 Thread burak serdar
I don't think this case really applies here. I get that comparison of
a==b may or may not be true. The problem is that if a==b at some point
in a program, it should be the case that a==b for all other cases in
that same program. That is, if a==b, then
interface{}(a)==interface{}(b), and vice versa. But what we have here
is a!=b but interface{}(a)==interface{}(b)

On Thu, Feb 22, 2024 at 9:50 AM Axel Wagner
 wrote:
>
> Hm actually, the spec allows for this, technically speaking: 
> https://go.dev/ref/spec#Comparison_operators
>
> > Pointers to distinct zero-size variables may or may not be equal.
>
> Arguably, this genuinely would allow comparison of pointers to zero-sized 
> variables to have any behavior whatsoever (including being random). But it 
> certainly is confusing.
>
>
> On Thu, Feb 22, 2024 at 5:46 PM Axel Wagner  
> wrote:
>>
>> I see. Sorry, I was jumping to conclusions and didn't quite get what you 
>> mean. That is my fault.
>>
>> I agree that this looks confusing and is arguably a bug. I filed 
>> https://github.com/golang/go/issues/65878, thanks for pointing it out.
>>
>> On Thu, Feb 22, 2024 at 5:20 PM burak serdar  wrote:
>>>
>>> Creating  an interface is not creating a pointer to a zero sized variable.
>>>
>>> a==b  prints false. That means, a and b point to different locations
>>> Bar(a)==Bar(b) prints true. If a!=b, then Bar(a) must be different from 
>>> Bar(b)
>>>
>>> On Thu, Feb 22, 2024 at 9:15 AM Axel Wagner
>>>  wrote:
>>> >
>>> > If you expect that, you are misreading the spec. There is no guarantee of 
>>> > any behavior here. An implementation is allowed to flip a coin, every 
>>> > time you create a pointer to a zero-sized variable, and either return a 
>>> > unique pointer or a singleton. I think you may assume that  == , 
>>> > always. But apart from that, who knows.
>>> >
>>> > Zero-sized variables *may* have the same address. They don't *have* to.
>>> >
>>> > On Thu, Feb 22, 2024 at 5:12 PM burak serdar  wrote:
>>> >>
>>> >> On Thu, Feb 22, 2024 at 9:00 AM Axel Wagner
>>> >>  wrote:
>>> >> >
>>> >> > Note that in the Spec section I quoted above it says "Two distinct 
>>> >> > zero-size variables may have the same address in memory" (emphasis 
>>> >> > mine).
>>> >> > There is no guarantee, that all zero-sized values have the same 
>>> >> > address (otherwise, you'd get into inefficiencies when taking the 
>>> >> > address of a zero-sized field in a larger struct, or when converting a 
>>> >> > zero-capacity slice into an array-pointer). But it is allowed.
>>> >> > If you require two pointers returned from different code paths to be 
>>> >> > different, for correctness, then you have to make them point at 
>>> >> > something that has non-zero size. Otherwise, all potential 
>>> >> > combinations are valid according to the spec.
>>> >>
>>> >> Yes. But in that case, you'd expect either  a==b and Bar(a)==Bar(b) to
>>> >> be both true, or both false. In this case, one is true and the other
>>> >> is not.
>>> >>
>>> >>
>>> >> >
>>> >> > On Thu, Feb 22, 2024 at 4:53 PM burak serdar  
>>> >> > wrote:
>>> >> >>
>>> >> >> The compiler can allocate the same address for empty structs, so I
>>> >> >> actually expected a==b to be true, not false. However, there's
>>> >> >> something more interesting going on here because:
>>> >> >>
>>> >> >> a := {}
>>> >> >> b := {}
>>> >> >> fmt.Printf("%t\n", *a == *b)
>>> >> >> fmt.Printf("%t\n", a == b)
>>> >> >> fmt.Printf("%p %p\n", a, b)
>>> >> >> x := Bar(a)
>>> >> >> y := Bar(b)
>>> >> >> fmt.Printf("%t\n", Bar(a) == Bar(b))
>>> >> >> fmt.Printf("%t\n", x == y)
>>> >> >>
>>> >> >> Prints:
>>> >> >>
>>> >> >> true
>>> >> >> true
>>> >> >> 0x58e360 0x58e360 // Note that a and be are pointing to the same 
>>> >> >> address
>>> >> >> true
>>> >> >> true
>>> >> >>
>>> >> >>
>>> >> >> But:
>>> >> >> a := {}
>>> >> >> b := {}
>>> >> >> fmt.Printf("%t\n", *a == *b)
>>> >> >> fmt.Printf("%t\n", a == b)
>>> >> >> //fmt.Printf("%p %p\n", a, b)  // Comment out the print
>>> >> >> x := Bar(a)
>>> >> >> y := Bar(b)
>>> >> >> fmt.Printf("%t\n", Bar(a) == Bar(b))
>>> >> >> fmt.Printf("%t\n", x == y)
>>> >> >>
>>> >> >>
>>> >> >> Prints:
>>> >> >>
>>> >> >> true
>>> >> >> false
>>> >> >> true
>>> >> >> true
>>> >> >>
>>> >> >>
>>> >> >> On Thu, Feb 22, 2024 at 3:56 AM Brien Colwell  
>>> >> >> wrote:
>>> >> >> >
>>> >> >> > I'm confused by this output. It appears that the interface of two 
>>> >> >> > different pointers to an empty struct are equal. In all other 
>>> >> >> > cases, interface equality seems to be the pointer equality. What's 
>>> >> >> > going on in the empty struct case?
>>> >> >> >
>>> >> >> > ```
>>> >> >> > package main
>>> >> >> >
>>> >> >> > import "fmt"
>>> >> >> >
>>> >> >> > type Foo struct {
>>> >> >> > }
>>> >> >> >
>>> >> >> > func (self *Foo) Hello() {
>>> >> >> > }
>>> >> >> >
>>> >> >> > type FooWithValue struct {
>>> >> >> > A int
>>> >> >> > }
>>> >> >> >
>>> >> >> > func (self *FooWithValue) Hello() {
>>> >> >> > }
>>> >> 

Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-22 Thread burak serdar
Creating  an interface is not creating a pointer to a zero sized variable.

a==b  prints false. That means, a and b point to different locations
Bar(a)==Bar(b) prints true. If a!=b, then Bar(a) must be different from Bar(b)

On Thu, Feb 22, 2024 at 9:15 AM Axel Wagner
 wrote:
>
> If you expect that, you are misreading the spec. There is no guarantee of any 
> behavior here. An implementation is allowed to flip a coin, every time you 
> create a pointer to a zero-sized variable, and either return a unique pointer 
> or a singleton. I think you may assume that  == , always. But apart from 
> that, who knows.
>
> Zero-sized variables *may* have the same address. They don't *have* to.
>
> On Thu, Feb 22, 2024 at 5:12 PM burak serdar  wrote:
>>
>> On Thu, Feb 22, 2024 at 9:00 AM Axel Wagner
>>  wrote:
>> >
>> > Note that in the Spec section I quoted above it says "Two distinct 
>> > zero-size variables may have the same address in memory" (emphasis mine).
>> > There is no guarantee, that all zero-sized values have the same address 
>> > (otherwise, you'd get into inefficiencies when taking the address of a 
>> > zero-sized field in a larger struct, or when converting a zero-capacity 
>> > slice into an array-pointer). But it is allowed.
>> > If you require two pointers returned from different code paths to be 
>> > different, for correctness, then you have to make them point at something 
>> > that has non-zero size. Otherwise, all potential combinations are valid 
>> > according to the spec.
>>
>> Yes. But in that case, you'd expect either  a==b and Bar(a)==Bar(b) to
>> be both true, or both false. In this case, one is true and the other
>> is not.
>>
>>
>> >
>> > On Thu, Feb 22, 2024 at 4:53 PM burak serdar  wrote:
>> >>
>> >> The compiler can allocate the same address for empty structs, so I
>> >> actually expected a==b to be true, not false. However, there's
>> >> something more interesting going on here because:
>> >>
>> >> a := {}
>> >> b := {}
>> >> fmt.Printf("%t\n", *a == *b)
>> >> fmt.Printf("%t\n", a == b)
>> >> fmt.Printf("%p %p\n", a, b)
>> >> x := Bar(a)
>> >> y := Bar(b)
>> >> fmt.Printf("%t\n", Bar(a) == Bar(b))
>> >> fmt.Printf("%t\n", x == y)
>> >>
>> >> Prints:
>> >>
>> >> true
>> >> true
>> >> 0x58e360 0x58e360 // Note that a and be are pointing to the same address
>> >> true
>> >> true
>> >>
>> >>
>> >> But:
>> >> a := {}
>> >> b := {}
>> >> fmt.Printf("%t\n", *a == *b)
>> >> fmt.Printf("%t\n", a == b)
>> >> //fmt.Printf("%p %p\n", a, b)  // Comment out the print
>> >> x := Bar(a)
>> >> y := Bar(b)
>> >> fmt.Printf("%t\n", Bar(a) == Bar(b))
>> >> fmt.Printf("%t\n", x == y)
>> >>
>> >>
>> >> Prints:
>> >>
>> >> true
>> >> false
>> >> true
>> >> true
>> >>
>> >>
>> >> On Thu, Feb 22, 2024 at 3:56 AM Brien Colwell  wrote:
>> >> >
>> >> > I'm confused by this output. It appears that the interface of two 
>> >> > different pointers to an empty struct are equal. In all other cases, 
>> >> > interface equality seems to be the pointer equality. What's going on in 
>> >> > the empty struct case?
>> >> >
>> >> > ```
>> >> > package main
>> >> >
>> >> > import "fmt"
>> >> >
>> >> > type Foo struct {
>> >> > }
>> >> >
>> >> > func (self *Foo) Hello() {
>> >> > }
>> >> >
>> >> > type FooWithValue struct {
>> >> > A int
>> >> > }
>> >> >
>> >> > func (self *FooWithValue) Hello() {
>> >> > }
>> >> >
>> >> > type Bar interface {
>> >> > Hello()
>> >> > }
>> >> >
>> >> > func main() {
>> >> > a := {}
>> >> > b := {}
>> >> > fmt.Printf("%t\n", *a == *b)
>> >> > fmt.Printf("%t\n", a == b)
>> >> > fmt.Printf("%t\n", Bar(a) == Bar(b))
>> >> >
>> >> > c := {A: 1}
>> >> > d := {A: 1}
>> >> > fmt.Printf("%t\n", *c == *d)
>> >> > fmt.Printf("%t\n", c == d)
>> >> > fmt.Printf("%t\n", Bar(c) == Bar(d))
>> >> > }
>> >> > ```
>> >> >
>> >> > Prints (emphasis added on the strange case):
>> >> >
>> >> > ```
>> >> > true
>> >> > false
>> >> > **true**
>> >> > true
>> >> > false
>> >> > false
>> >> > ```
>> >> >
>> >> >
>> >> > --
>> >> > 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/d93760c9-61a7-4a3c-9b5c-d89f023d2253n%40googlegroups.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/CAMV2Rqrq21ymUJ00ni_JV%3Dkv6itqZg51GoWM5zJNjcGU1BKcuA%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 

Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-22 Thread burak serdar
On Thu, Feb 22, 2024 at 9:00 AM Axel Wagner
 wrote:
>
> Note that in the Spec section I quoted above it says "Two distinct zero-size 
> variables may have the same address in memory" (emphasis mine).
> There is no guarantee, that all zero-sized values have the same address 
> (otherwise, you'd get into inefficiencies when taking the address of a 
> zero-sized field in a larger struct, or when converting a zero-capacity slice 
> into an array-pointer). But it is allowed.
> If you require two pointers returned from different code paths to be 
> different, for correctness, then you have to make them point at something 
> that has non-zero size. Otherwise, all potential combinations are valid 
> according to the spec.

Yes. But in that case, you'd expect either  a==b and Bar(a)==Bar(b) to
be both true, or both false. In this case, one is true and the other
is not.


>
> On Thu, Feb 22, 2024 at 4:53 PM burak serdar  wrote:
>>
>> The compiler can allocate the same address for empty structs, so I
>> actually expected a==b to be true, not false. However, there's
>> something more interesting going on here because:
>>
>> a := {}
>> b := {}
>> fmt.Printf("%t\n", *a == *b)
>> fmt.Printf("%t\n", a == b)
>> fmt.Printf("%p %p\n", a, b)
>> x := Bar(a)
>> y := Bar(b)
>> fmt.Printf("%t\n", Bar(a) == Bar(b))
>> fmt.Printf("%t\n", x == y)
>>
>> Prints:
>>
>> true
>> true
>> 0x58e360 0x58e360 // Note that a and be are pointing to the same address
>> true
>> true
>>
>>
>> But:
>> a := {}
>> b := {}
>> fmt.Printf("%t\n", *a == *b)
>> fmt.Printf("%t\n", a == b)
>> //fmt.Printf("%p %p\n", a, b)  // Comment out the print
>> x := Bar(a)
>> y := Bar(b)
>> fmt.Printf("%t\n", Bar(a) == Bar(b))
>> fmt.Printf("%t\n", x == y)
>>
>>
>> Prints:
>>
>> true
>> false
>> true
>> true
>>
>>
>> On Thu, Feb 22, 2024 at 3:56 AM Brien Colwell  wrote:
>> >
>> > I'm confused by this output. It appears that the interface of two 
>> > different pointers to an empty struct are equal. In all other cases, 
>> > interface equality seems to be the pointer equality. What's going on in 
>> > the empty struct case?
>> >
>> > ```
>> > package main
>> >
>> > import "fmt"
>> >
>> > type Foo struct {
>> > }
>> >
>> > func (self *Foo) Hello() {
>> > }
>> >
>> > type FooWithValue struct {
>> > A int
>> > }
>> >
>> > func (self *FooWithValue) Hello() {
>> > }
>> >
>> > type Bar interface {
>> > Hello()
>> > }
>> >
>> > func main() {
>> > a := {}
>> > b := {}
>> > fmt.Printf("%t\n", *a == *b)
>> > fmt.Printf("%t\n", a == b)
>> > fmt.Printf("%t\n", Bar(a) == Bar(b))
>> >
>> > c := {A: 1}
>> > d := {A: 1}
>> > fmt.Printf("%t\n", *c == *d)
>> > fmt.Printf("%t\n", c == d)
>> > fmt.Printf("%t\n", Bar(c) == Bar(d))
>> > }
>> > ```
>> >
>> > Prints (emphasis added on the strange case):
>> >
>> > ```
>> > true
>> > false
>> > **true**
>> > true
>> > false
>> > false
>> > ```
>> >
>> >
>> > --
>> > 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/d93760c9-61a7-4a3c-9b5c-d89f023d2253n%40googlegroups.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/CAMV2Rqrq21ymUJ00ni_JV%3Dkv6itqZg51GoWM5zJNjcGU1BKcuA%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/CAMV2RqrRNT9CmWbhMYTOV4fmnAvLULTw0cVe%3Dd4adfTLO6gQoA%40mail.gmail.com.


Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-22 Thread burak serdar
The compiler can allocate the same address for empty structs, so I
actually expected a==b to be true, not false. However, there's
something more interesting going on here because:

a := {}
b := {}
fmt.Printf("%t\n", *a == *b)
fmt.Printf("%t\n", a == b)
fmt.Printf("%p %p\n", a, b)
x := Bar(a)
y := Bar(b)
fmt.Printf("%t\n", Bar(a) == Bar(b))
fmt.Printf("%t\n", x == y)

Prints:

true
true
0x58e360 0x58e360 // Note that a and be are pointing to the same address
true
true


But:
a := {}
b := {}
fmt.Printf("%t\n", *a == *b)
fmt.Printf("%t\n", a == b)
//fmt.Printf("%p %p\n", a, b)  // Comment out the print
x := Bar(a)
y := Bar(b)
fmt.Printf("%t\n", Bar(a) == Bar(b))
fmt.Printf("%t\n", x == y)


Prints:

true
false
true
true


On Thu, Feb 22, 2024 at 3:56 AM Brien Colwell  wrote:
>
> I'm confused by this output. It appears that the interface of two different 
> pointers to an empty struct are equal. In all other cases, interface equality 
> seems to be the pointer equality. What's going on in the empty struct case?
>
> ```
> package main
>
> import "fmt"
>
> type Foo struct {
> }
>
> func (self *Foo) Hello() {
> }
>
> type FooWithValue struct {
> A int
> }
>
> func (self *FooWithValue) Hello() {
> }
>
> type Bar interface {
> Hello()
> }
>
> func main() {
> a := {}
> b := {}
> fmt.Printf("%t\n", *a == *b)
> fmt.Printf("%t\n", a == b)
> fmt.Printf("%t\n", Bar(a) == Bar(b))
>
> c := {A: 1}
> d := {A: 1}
> fmt.Printf("%t\n", *c == *d)
> fmt.Printf("%t\n", c == d)
> fmt.Printf("%t\n", Bar(c) == Bar(d))
> }
> ```
>
> Prints (emphasis added on the strange case):
>
> ```
> true
> false
> **true**
> true
> false
> false
> ```
>
>
> --
> 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/d93760c9-61a7-4a3c-9b5c-d89f023d2253n%40googlegroups.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/CAMV2Rqrq21ymUJ00ni_JV%3Dkv6itqZg51GoWM5zJNjcGU1BKcuA%40mail.gmail.com.


Re: [go-nuts] Equality of interface of an empty struct - why?

2024-02-22 Thread 'Axel Wagner' via golang-nuts
>From the spec :

> A struct or array type has size zero if it contains no fields (or
elements, respectively) that have a size greater than zero. Two distinct
zero-size variables may have the same address in memory.

On Thu, Feb 22, 2024 at 11:56 AM Brien Colwell  wrote:

> I'm confused by this output. It appears that the interface of two
> different pointers to an empty struct are equal. In all other cases,
> interface equality seems to be the pointer equality. What's going on in the
> empty struct case?
>
> ```
> package main
>
> import "fmt"
>
> type Foo struct {
> }
>
> func (self *Foo) Hello() {
> }
>
> type FooWithValue struct {
> A int
> }
>
> func (self *FooWithValue) Hello() {
> }
>
> type Bar interface {
> Hello()
> }
>
> func main() {
> a := {}
> b := {}
> fmt.Printf("%t\n", *a == *b)
> fmt.Printf("%t\n", a == b)
> fmt.Printf("%t\n", Bar(a) == Bar(b))
>
> c := {A: 1}
> d := {A: 1}
> fmt.Printf("%t\n", *c == *d)
> fmt.Printf("%t\n", c == d)
> fmt.Printf("%t\n", Bar(c) == Bar(d))
> }
> ```
>
> Prints (emphasis added on the strange case):
>
> ```
> true
> false
> **true**
> true
> false
> false
> ```
>
>
> --
> 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/d93760c9-61a7-4a3c-9b5c-d89f023d2253n%40googlegroups.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/CAEkBMfGOHMd%3D4R2QC%2BRKTimBZq%3DThsz8n2wORxYFxQMRgtyCsQ%40mail.gmail.com.


[go-nuts] Equality of interface of an empty struct - why?

2024-02-22 Thread Brien Colwell
I'm confused by this output. It appears that the interface of two different 
pointers to an empty struct are equal. In all other cases, interface 
equality seems to be the pointer equality. What's going on in the empty 
struct case?

```
package main

import "fmt"

type Foo struct {
}

func (self *Foo) Hello() {
}

type FooWithValue struct {
A int
}

func (self *FooWithValue) Hello() {
}

type Bar interface {
Hello()
}

func main() {
a := {}
b := {}
fmt.Printf("%t\n", *a == *b)
fmt.Printf("%t\n", a == b)
fmt.Printf("%t\n", Bar(a) == Bar(b))

c := {A: 1}
d := {A: 1}
fmt.Printf("%t\n", *c == *d)
fmt.Printf("%t\n", c == d)
fmt.Printf("%t\n", Bar(c) == Bar(d))
}
```

Prints (emphasis added on the strange case):

```
true
false
**true**
true
false
false
```


-- 
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/d93760c9-61a7-4a3c-9b5c-d89f023d2253n%40googlegroups.com.