On Thu, 20 Jun 2024 at 12:28, Oliver Eikemeier <eikeme...@fillmore-labs.com>
wrote:

> Let me start with this: I’m fine with the behavior, it is exotic enough
> that even the optimizer should be allowed to assume something that doesn’t
> hold during runtime, since it simplifies things.
>
> What I think is at least surprising and at worst lacking is the
> documentation.
>
> It mentions “pointers” (plural) to zero-sized variables, but for this
> behavior it is sufficient when only one pointer derives from a pointer to a
> zero-sized variable, as demonstrated in the example below.
>

Re-visiting your example, it is indeed interesting that I realized before.
I'll note that you need to involve `unsafe.Pointer` to observe this, as you
may not compare pointers to different types. And `unsafe.Pointer`'s
behaviors are somewhat left up to the implementation.

The spec ays: <https://go.dev/ref/spec#Package_unsafe>

A Pointer is a pointer type <https://go.dev/ref/spec#Pointer_types> but a
> Pointer value may not be dereferenced
> <https://go.dev/ref/spec#Address_operators>. Any pointer or value of core
> type <https://go.dev/ref/spec#Core_types> uintptr can be converted
> <https://go.dev/ref/spec#Conversions> to a type of core type Pointer and
> vice versa. The effect of converting between Pointer and uintptr is
> implementation-defined.


The thing that stands out is that it leaves the effect of converting to
`uintptr` up to the implementation, but nothing else. So any other rule, as
far as the language is concerned, should be derived from the rules for
pointer types (except that they can not be dereferenced).

One contradiction here is that this section references the definition of a
pointer type, which says

A pointer type denotes the set of all pointers to variables
> <https://go.dev/ref/spec#Variables> of a given type, called the *base
> type* of the pointer.
>

This contradicts the nature of `unsafe.Pointer`, though, which does not
have a base type. That difference is what causes the trouble: When the spec
defines pointer comparisons by

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 <https://go.dev/ref/spec#Size_and_alignment_guarantees>
> variables may or may not be equal.


We can see that 1. `unsafe.Pointer` is definitionally a pointer type, 2. in
your example, the two `unsafe.Pointers` do not point to the same variable
and do not have the value `nil` and 3. are not pointing at distinct
zero-sized variables. So their comparison should be `false`, which is what
your example observes.

All of this would be fine. What makes your example confusing is that you
use `println` to output them and see that they "have the same value". For
that, we need to look at the definition of `println`
<https://go.dev/ref/spec#Bootstrapping>:

Current implementations provide several built-in functions useful during
> bootstrapping. These functions are documented for completeness but are not
> guaranteed to stay in the language. They do not return a result.
>
> Function   Behavior
>
> print      prints all arguments; formatting of arguments is 
> implementation-specific
> println    like print but prints spaces between arguments and a newline at 
> the end
>
> Implementation restriction: print and println need not accept arbitrary
> argument types, but printing of boolean, numeric, and string types
> <https://go.dev/ref/spec#Types> must be supported.
>
Notably, this says nothing about what happens if you pass a pointer type.
That is thus left up to the implementation. In effect, it does the same as
`fmt.Println` ultimately: It converts the pointer to `uintptr`, which as
we've seen above is left to the implementation.

Note that if you *don't* convert an `unsafe.Pointer` to `uintptr`, you have
no way to argue that they "are actually equal". And if you don't use
`unsafe.Pointer` you have no way to compare pointers to variables of
different types. So, the only way to observe that behavior is to enter what
is implementation-defined.

So, yes. Your example is interesting, but still within spec.

I’m advocating for at least a FAQ article,
>

I tend to agree, though I'm not sure how to phrase that, beyond saying "do
not make any assumptions about the identity pointers to zero-sized
variables or with zero-sized base types or that where derived from one of
those" and I'm not sure how helpful that is.


> but also think the specification should be adapted, for clarity but also
> for the fact that only one pointer pointing to a zero-sized variable can
> compare differently to anything over time, even things having the same
> address value.
>

Note that "address value" is not something that exists within the spec. As
for clarifying the spec here, maybe. I do think the behavior is covered, as
I outlined above. And as above, I'm not sure how to clarify it further,
while still leaving up the space we want to left open.


>
> I do not believe the specification is clear on this. Otherwise I don’t
> think this is urgent. But it seems to pop up repeatedly.
>
> Cheers
> Oliver
>
> Am 19.06.2024 um 23:16 schrieb 'Axel Wagner' via golang-nuts <
> golang-nuts@googlegroups.com>:
>
> The spec says both. It says
>
>> Two distinct zero-size variables may have the same address in memory.
>
> And it says
>
>> Pointers to distinct zero-size variables may or may not be equal.
>
>
> The former means what you say. The latter means what Ian says.
>
> Then I have two pointers. Where in the spec is “the result of comparison
>> of pointers may change over time”?
>>
>
>> For example (Go Playground <https://go.dev/play/p/acknRHBvi0P>):
>>
>> func f3() {
>> var (
>> a  struct{}
>> b  int
>> aa = unsafe.Pointer(&a)
>> ba = unsafe.Pointer(&b)
>> eq = aa == ba
>> )
>>
>> println("&a:", aa)
>> println("&b:", ba)
>> println("&a == &b:", eq)
>> }
>>
>> gives
>>
>> &a: 0xc000046738
>> &b: 0xc000046738
>> &a == &b: false
>>
>> and &b is not even a pointer to a zero-sized variable.
>>
>
>

-- 
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/CAEkBMfHkff%3D8OrUM_nJ-K4Fs%3DypuwOqRV9tXfCYGj7UNhM95EQ%40mail.gmail.com.

Reply via email to