(apologies for the abundance of grammatical and spelling errors that
occurred during editing and of course only became visible after hitting
"send")

On Thu, 20 Jun 2024 at 13:24, Axel Wagner <axel.wagner...@googlemail.com>
wrote:

> 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/CAEkBMfE0oAV4uQYVvWLwG1uBxgnum4r7-MdBqu8%2BDfURWg_FUw%40mail.gmail.com.

Reply via email to