Skip to content

spec: Conversions_from_slice_to_array_pointer: clarify behavior for subslices #47599

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
nevkontakte opened this issue Aug 8, 2021 · 4 comments · Fixed by ferrmin/go#124
Closed
Labels
Documentation Issues describing a change to documentation. FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@nevkontakte
Copy link
Contributor

Currently the spec says the following:

go/doc/go_spec.html

Lines 4324 to 4326 in 72ab3ff

Converting a slice to an array pointer yields a pointer to the underlying array of the slice.
If the <a href="#Length_and_capacity">length</a> of the slice is less than the length of the array,
a <a href="#Run_time_panics">run-time panic</a> occurs.

However, it is not clear what "underlying array" should mean for a slice created as a subslice of another array. Consider the following code:

v := make([]byte, 4)
v0 := (*[2]byte)(v[2:4])

Several interpretations are possible:

  1. Operation allowed, &v0[0] == &v[2].
  2. Operation panics because v[2:4] doesn't point at the beginning of the v's underlying array.
  3. Operation allowed, &v0[0] == &v[0], since the "underlying array" is interpreted as the block of memory that was originally allocated for v. This is perhaps counter-intuitive, but not prohibited by the spec.

In my experimentation #1 is the actual behavior, and it makes sense, since in a general case the user has no way of knowing whether a slice is sharing its underlying array with any other slice and how they may be overlapping. Formalizing it in the spec would be useful to ensure third-party Go implementations behave similarly.

CC @flimzy since it's relevant to gopherjs/gopherjs#1043.

@randall77
Copy link
Contributor

One more example might help.

s1 := (*[1]byte)(s[1:]) // &s1[0] == &s[1]

@seankhliao seankhliao changed the title spec: spec: Conversions_from_slice_to_array_pointer: clarify behavior for subslices spec: Conversions_from_slice_to_array_pointer: clarify behavior for subslices Aug 8, 2021
@cuonglm
Copy link
Member

cuonglm commented Aug 8, 2021

While I agree with adding more example, I don't think the spec is not clear. In the "Slice Expressions" section, it's well defined what "underlying array" mean for subslice https://golang.org/ref/spec#Slice_expressions, example from the spec:

var a [10]int
s1 := a[3:7]   // underlying array of s1 is array a; &s1[2] == &a[5]
s2 := s1[1:4]  // underlying array of s2 is underlying array of s1 which is array a; &s2[1] == &a[5]
s2[1] = 42     // s2[1] == s1[2] == a[5] == 42; they all refer to the same underlying array element

@gopherbot
Copy link
Contributor

Change https://golang.org/cl/340351 mentions this issue: doc: add example for conversion from slice expressions to array ptr

@nevkontakte
Copy link
Contributor Author

nevkontakte commented Aug 8, 2021

@cuonglm arguably the way spec describes underlying array leaves the meaning of "yields a pointer to the underlying array of the slice" ambiguous. Paraphrasing the example you've referenced:

var a1 [10]int
s1 := a1[:]  // underlying array of s1 is a, &a1[0] == &s1[0]
s2 := s[5:] // underlying array of s2 is still a1 as per spec, but &a1[0] != &s2[0] and s2 doesn't contain information on where a1 begins.
a2 := (*[5]int)(s2) // not a pointer to a1: unsafe.Pointer(&a1) != unsafe.Pointer(a2)

So if a1 is considered to be the underlying array of both s2 and s1, then the conversion did not return a pointer to a1, it returned a pointer to inside of a1.

However, that's quite a nitpick on my part, and the additional example resolves the ambiguity. Thanks for a quick fix!

@dmitshur dmitshur added Documentation Issues describing a change to documentation. NeedsFix The path to resolution is known, but the work has not been done. labels Aug 12, 2021
@dmitshur dmitshur added this to the Go1.17 milestone Aug 12, 2021
@golang golang locked and limited conversation to collaborators Aug 12, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Documentation Issues describing a change to documentation. FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants