In Go 1.21 we are introducing some new functions in the unsafe package: unsafe.Slice, unsafe.SliceData, unsafe.String, unsafe.StringData. It should be possible to access this functionality through the reflect package as well.

The value returned by unsafe.SliceData is already available by calling the reflect.Value.Pointer method.

I propose that we extend reflect.Value.Pointer so that if it is called on a value of kind String, it returns the equivalent of unsafe.StringData.

The equivalent to unsafe.String is simply reflect.ValueOf(unsafe.String((*byte)(vp.UnsafePointer()), n)), so I don't think we need to add anything for that.

I propose one new function:

package reflect

// UnsafeSlice returns a Value representing a slice whose underlying data starts at vp,
// with length and capacity equal to n. vp.Kind() must be Pointer.
// The returned slice will have element type vp.Type().Elem().
// This is like unsafe.Slice.
func UnsafeSlice(vp Value, n int) Value

(edited to change function name from Slice to UnsafeSlice`)

Comment From: bcmills

It seems to me that the new functionality is to MakeSlice as NewAt is to New. So I suggest:

func SliceAt(typ Type, p unsafe.Pointer, len int) Value

That has the additional advantage of passing through the type unsafe.Pointer, which clarifies that it is in fact unsafe.

Comment From: rittneje

Why does the proposed reflect.Slice (or reflect.SliceAt) require the length and capacity to be the same instead of having two separate parameters like reflect.MakeSlice?

Comment From: DeedleFake

Those functions were introduced starting in 1.17 and then more in 1.20.

The equivalent to unsafe.String is simply reflect.ValueOf(unsafe.String(vp.Pointer(), n)), so I don't think we need to add anything for that.

That won't work. unsafe.String() requires a *byte, not a uintptr. The conversion requires first converting through an unsafe.Pointer, so I think having an equivalent top-level function makes sense for that one, too. It's not really any different from a slice otherwise except for the type always being the same:

reflect.ValueOf(unsafe.String((*byte)(unsafe.Pointer(v.Pointer())), v.Len()))
reflect.ValueOf(unsafe.Slice((*T)(unsafe.Pointer(v.Pointer())), v.Len()))

Comment From: bcmills

Why does the proposed reflect.Slice (or reflect.SliceAt) require the length and capacity to be the same … ?

Because unsafe.Slice does too. Most of the time you do want them to be the same, and if you want to reduce the capacity that's easy enough to do as a separate operation (via SetCap).

Comment From: bcmills

For the string case,

reflect.ValueOf(unsafe.String(v.Interface().(*byte), v.Len()))

or

reflect.ValueOf(unsafe.String((*byte)(v.UnsafePointer()), v.Len()))

will often suffice.

Comment From: cuonglm

I think the function name should be UnsafeSlice instead of Slice.

Slice is already taken as a Kind.

Comment From: gopherbot

Change https://go.dev/cl/516597 mentions this issue: reflect: add UnsafeSlice

Comment From: gopherbot

Change https://go.dev/cl/516596 mentions this issue: reflect: handle String kind in Value.Pointer

Comment From: rsc

I think the function name should be UnsafeSlice instead of Slice. Slice is already taken as a Kind.

Another reason is that these are in fact unsafe, so the name should begin with Unsafe to distinguish it from the normal, safe reflect API.

Comment From: rsc

It seems like we should also update UnsafePointer to handle String (not just update Pointer).

Comment From: rsc

This proposal has been added to the active column of the proposals project and will now be reviewed at the weekly proposal review meetings. — rsc for the proposal review group

Comment From: rsc

Have all remaining concerns about this proposal been addressed?

Two parts to the proposal.

First, add func UnsafeSlice, mimicking unsafe.Slice.

Second, update Value.Pointer and Value.UnsafePointer to handle String.

Comment From: bcmills

I don't think the signature concern in https://github.com/golang/go/issues/61308#issuecomment-1631737298 has been addressed yet.

The other functions and methods in the reflect package that use the word Unsafe still explicitly require the use of the unsafe package, but

func Slice(vp Value, n int) Value

(as described in https://github.com/golang/go/issues/61308#issue-1799861635) does not have that property.

Comment From: ianlancetaylor

I'm not sure that's quite true of the existing reflect.Value.UnsafePointer method, which does return a value of type unsafe.Pointer but can be used without importing the unsafe package.

Note that the proposed function is now named UnsafeSlice rather than Slice.

Comment From: aclements

I also prefer @bcmills ' alternate signature. It has the clear advantage of using unsafe.Pointer, and I suspect in practice it will be more common that callers will have an unsafe.Pointer already, rather than a Value, so it will save the conversion (though they can convert either way).

Comment From: rsc

Have all remaining concerns about this proposal been addressed?

Two parts to the proposal.

First, add func SliceAt, analogous to NewAt (which probably should have been called ValueAt) but for slices:

func SliceAt(typ Type, p unsafe.Pointer, len int) Value

Second, update Value.Pointer and Value.UnsafePointer to handle String.

Comment From: rsc

Based on the discussion above, this proposal seems like a likely accept. — rsc for the proposal review group

Two parts to the proposal.

First, add func SliceAt, analogous to NewAt (which probably should have been called ValueAt) but for slices:

func SliceAt(typ Type, p unsafe.Pointer, len int) Value

Second, update Value.Pointer and Value.UnsafePointer to handle String.

Comment From: gopherbot

Change https://go.dev/cl/572117 mentions this issue: reflect: Value.Pointer and Value.UnsafePointer handle String

Comment From: gopherbot

Change https://go.dev/cl/572118 mentions this issue: reflect: add SliceAt

Comment From: cuonglm

Does reflect.SliceAt do all the runtime validations that unsafe.Slice do? For example, should this code panic?

_ = SliceAt(TypeOf(0), unsafe.Pointer((*int)(nil)), 1)

Comment From: rsc

Yes, reflect.SliceAt should be no more unsafe than unsafe.Slice. So it should do the same validations.

Comment From: rsc

No change in consensus, so accepted. 🎉 This issue now tracks the work of implementing the proposal. — rsc for the proposal review group

Two parts to the proposal.

First, add func SliceAt, analogous to NewAt (which probably should have been called ValueAt) but for slices:

func SliceAt(typ Type, p unsafe.Pointer, len int) Value

Second, update Value.Pointer and Value.UnsafePointer to handle String.

Comment From: gopherbot

Change https://go.dev/cl/575956 mentions this issue: reflect: add missing String case in Value.UnsafePointer doc

Comment From: gopherbot

Change https://go.dev/cl/592197 mentions this issue: doc/next: improve description of proposal 61308