> 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 
<https://go.dev/play/p/MgtUz2em65A>.

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 <mr...@renich.org> 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 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...@googlegroups.com.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/golang-nuts/Zd41i3rHLskqBuef%40basil.wdw
>> .
>>
>
> -- 
>
> 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/CAEkBMfHVuxSduyWHG20DjzG1jvE0P06fEqC_FyHdDEWewjOjTg%40mail.gmail.com
>  
> <https://groups.google.com/d/msgid/golang-nuts/CAEkBMfHVuxSduyWHG20DjzG1jvE0P06fEqC_FyHdDEWewjOjTg%40mail.gmail.com?utm_medium=email&utm_source=footer>
> .
>
>
>

-- 
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/c7ead734-8ce6-4254-91ac-771b02e527ddn%40googlegroups.com.

Reply via email to