-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
unsafe: add Slice(ptr *T, len anyIntegerType) []T #19367
Comments
If we do this, we should figure out a way to exempt these new types from the Go 1 compatibility guarantee, so that we can change the representation of strings and slices in the future. I'm not sure how best to do that. |
@ianlancetaylor reflect.SliceHeader and reflect.StringHeader already try:
but the compat doc itself gives a strong exemption for all of unsafe:
ISTM that unsafe.{Slice,String} would already be exempted sufficiently. |
Go 2 seems like the time to think about this (and reflect.SliceHeader etc). -rsc for @golang/proposal-review |
This proposal seems a bit redundant with #13656. How much of the use-case is "create a string or slice aliasing C memory" vs. "manipulate existing strings and slices by tweaking header fields unsafely"? |
I'd like to suggest renewing consideration of this proposal for Go 1.14. I think it will be useful for users trying to address issues flagged by -d=checkptr. I'll also offer a counter-proposal that I think better addresses most end user needs in a more ergonomic manner:
[Edit: As discussed below, I'm now in favor of combining Slice's len/cap parameter into a single parameter.] This is a little less versatile than exposing the Header types, but I think it will minimize typing for most users, while also providing better type safety. We could also do both this proposal and my original one, if we want to still offer the full flexibility of the Header types. In that case, I would suggest renaming the types to SliceHeader and StringHeader, and reserve the shorter Slice and String identifiers for the constructor functions. |
I like that counter proposal API. |
A few additional thoughts to add to my counter proposal:
|
That API is closer to what I had suggested in https://golang.org/issue/13656#issuecomment-303216308, and we've been using that variant within Google for a couple of years now without complaints. If the type desired for the slice does not match the pointer that the user has (for example, if one is a cgo-generated type and the other is a native Go type), I'm assuming that the caller could do something like: var s = unsafe.Slice((*someGoType)(unsafe.Pointer(cPtr)), len, cap) to set the element type? |
I would leave it unspecified, but
That would certainly smooth out the call site in the (overwhelmingly common) case that |
Yeah, that's my thought. If a user wants to convert |
Ack, though my concern is if we panic by default, then users might come to rely on it panicking and not write their own checking. It would be easy to put the panic behind |
Can we instead do:
... with an optional cap. Where omitting cap means cap == len? |
@bradfitz Yeah, that's my additional thought #3 above. :) |
Hmm, good point. We could make it a throw! 😉 Or we could make it a |
It could, but it is a little inconvenient. And it is some inconsistent. |
I had considered that, and I still haven't ruled it out. But we had to pick something, and I don't think it's obvious returning nil in that case is necessarily better. It's also easier to relax an overly strict API than to restrict an overly lax one. My intuition is it the inconvenience, if any, will be minor. However, if actual use demonstrates that returning |
FWIW, I think it is obviously better — (Compare Ousterhout ch. 10, although I agree that it's not always clear.)
If that's the case, the documentation for That would leave open the possibility of changing the behavior in the future, whereas promising to panic does not. |
The specified behavior for unsafe.Slice is that it returns I agree that If others don't share my hesitancy and there's strong support for changing it to return
I think we can change the semantics as long as it's tied to the (I agree panicking is defined behavior, but my feeling is we've been somewhat lenient about that when it comes to Go 1 compat. I don't have concrete examples off hand though to point to.) |
Change https://golang.org/cl/329925 mentions this issue: |
Add unsafe.Add and unsafe.Slice to the list of built-in functions which are not permitted in statement context. The compiler and type checker already enforce this restriction, this just fixes a documentation oversight. For #19367. For #40481. Change-Id: Iabc63a8db048eaf40a5f5b5573fdf00b79d54119 Reviewed-on: https://go-review.googlesource.com/c/go/+/329925 Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Griesemer <gri@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Rob Pike <r@golang.org> TryBot-Result: Go Bot <gobot@golang.org>
Is it worth it to add an example for how to use this in the context of converting a string to a slice? I have a feeling people will look at the API and just use slice := unsafe.Slice((*byte)(unsafe.Pointer(&str)), len(str)) If I'm reading this correctly, the proper use is slice := unsafe.Slice((*byte)(unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&str)).Data)), len(str)) which is a bit unwieldy. It may be useful to have examples on this function in general. Also, from reading the documentation, |
Converting a string to a slice is fairly unsafe, and not really what this function is for, so I'm would vote against an example of that. The |
If this is not for converting to a slice, it may be worth explicitly mentioning that. I think garbage free string<->slice conversions are pretty valuable from a high-ish-performance perspective, e.g. hashing functions usually operate on slices, and often people have strings as input. In these cases, a library author can document that an input slice is not modified, and then offer corresponding non-copying string functions. In one of my own libraries, I explicitly document that a function uses I know I've seen many, many string<->slice implementations in Go libraries since 2012. Given that That said, if this is still a pattern we don't want to support, then documenting that w.r.t. the code block, now that you mention it's just a restatement in code, it's really obvious. Maybe changing the preceding line from
to
|
Well, maybe, but after all we don't usually document things to say what they are not for. We document them to say what they are for. I'm not denying that there are valid uses of converting a I sent https://golang.org/cl/332409 with your suggestion, we'll see what other people think. Thanks. |
Change https://golang.org/cl/332409 mentions this issue: |
Thank you, that reads more clearly to me! Good point on not mentioning what things are not for. I don't think the current docs imply what it is for (cgo?), more just that the function exists, but that's ok with me, I don't think I'm the intended user for the function at this point. :) |
For #19367 Change-Id: If0ff8ddba3b6b48e2e198cf3653e73284c7572a3 Reviewed-on: https://go-review.googlesource.com/c/go/+/332409 Trust: Ian Lance Taylor <iant@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Robert Griesemer <gri@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
Change https://golang.org/cl/338949 mentions this issue: |
For golang/go#19367 For golang/go#40481 Change-Id: I989d042a518a38fd24c0d14f9c78ae564e5799a2 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/338949 Trust: Ian Lance Taylor <iant@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com>
Change https://golang.org/cl/340549 mentions this issue: |
For golang/go#19367 For golang/go#40481 Change-Id: Id1aefd0696131842d480d9f9a5330c5ab221245a Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/340549 Trust: Ian Lance Taylor <iant@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com>
reflect.SliceHeader
andreflect.StringHeader
are clumsy to use because theirData
fields have typeuintptr
instead ofunsafe.Pointer
.This proposal is to add types
unsafe.Slice
andunsafe.String
as replacements. They would be declared just like their package reflect analogs, except withunsafe.Pointer
-typedData
fields:Additionally, I suggest that for the purposes of type conversion, we treat that
string
andunsafe.String
have the same underlying type, and also[]T
andunsafe.Slice
. For example, these would be valid:While the same results can be achieved using
unsafe.Pointer
conversions, by using direct conversions the compiler can provide a little extra type safety.The text was updated successfully, but these errors were encountered: