Keith, I think you've cracked it. It seems very simple in retrospect. 
Thanks.

On Tuesday, September 24, 2019 at 1:40:02 AM UTC+2, Keith Randall wrote:
>
> In the runtime we use structs like these, but with unsafe.Pointer data 
> fields (runtime.stringStruct and runtime.slice). They are much safer to use 
> than reflect's types with uintptr Data fields. Unfortunately we can't 
> change reflect's types because of the Go 1 compatibility guarantee.
>
> You can do the same thing the runtime does. Something like this would 
> work, and hopefully catch any future changes which would break the 
> implementation:
>
> type stringHeader struct {
> data unsafe.Pointer
> len  int
> }
> type sliceHeader struct {
> data unsafe.Pointer
> len  int
> cap  int
> }
>
> func init() {
> // Check to make sure string header is what reflect thinks it is.
> // They should be the same except for the type of the Data field.
> if unsafe.Sizeof(stringHeader{}) != unsafe.Sizeof(reflect.StringHeader{}) {
> panic("string layout has changed")
> }
> x := stringHeader{}
> y := reflect.StringHeader{}
> x.data = unsafe.Pointer(y.Data)
> y.Data = uintptr(x.data)
> x.len = y.Len
>
> // same for slice
> }
>
>
>
> On Monday, September 23, 2019 at 9:38:27 AM UTC-7, Robert Engels wrote:
>>
>> As someone that has worked with a lot of similar libraries in the HFT 
>> space - things like UnsafeString or FastString in Java I would caution 
>> against doing this in Go - especially as proposed here. Taking an immutable 
>> object like string and making it mutable by accident is a recipe for 
>> disaster. You are almost always better mapping a struct with accessors and 
>> letting Go escape analysis perform the work on the stack and keep the 
>> safety. 
>>
>>
>>
>> On Sep 23, 2019, at 10:09 AM, Francis <francis...@gmail.com> wrote:
>>
>> So I think the current state of unsafe conversions of string <-> []byte 
>> is roughly
>>
>> 1. Use the reflect Slice/StringHeader struct. These structs give you 
>> clear fields to set and read from. If the runtime representation of a 
>> string or []byte ever changes then these structs should change to reflect 
>> this (they have a non-backwards compatibility carve out in the comments). 
>> But this also means that you run into all these exotic problems because 
>> these two structs have a `uintpr` an `unsafe.Pointer` so for a short time 
>> the GC won't realise you are reading/writing a pointer. This makes correct 
>> use of these structs very difficult.
>> 2. You can just cast between these two types going through 
>> `unsafe.Pointer` on the way. This works, because these two types have 
>> almost identical layouts. We don't use any uintptr at all and so the GC 
>> probably won't get confused. But, if the representations of string or 
>> []byte ever change then you code breaks silently, and could have very 
>> weird/hard to track down problems.
>>
>> So I don't think `neither is safer than the other` is quite the right 
>> description in this context. They both have problems, so they are both 
>> not-perfect. But their problems are quite distinct. At the least if we 
>> choose one over the other we can describe clearly which set of problems we 
>> want to have.
>>
>> My hope was that someone had thought through these problems and could 
>> indicate the right way to do it.
>>
>> On a related note. I was trying to track down where the 
>> Slice/StringHeader was first introduced. It was a long time ago 
>>
>> <Rob Pike> (10 years ago) 29e6eb21ec  (HEAD)
>>
>> make a description of the slice header public
>>
>> R=rsc
>> DELTA=18  (3 added, 0 deleted, 15 changed)
>> OCL=31086
>> CL=31094
>>
>> Although I couldn't open that CL in gerrit (I assume user-error). From 
>> reading the commit I think the intention was for these header structs to be 
>> used for this or similar things. But the data was represented as a uintptr 
>> and a comment explicitly states that these structs are of no use without 
>> `unsafe.Pointer`. I have seen roughly three other CL which try to change 
>> the data field to `unsafe.Pointer` but are rejected because they change the 
>> reflect packages API.
>>
>> There is also this issue
>>
>> https://github.com/golang/go/issues/19367
>>
>> Which proposes that Slice/StringHeader be moved/duplicated in unsafe and 
>> use `unsafe.Pointer`. As far as I can tell once we have this then all the 
>> subtle problems disappear and lovingly crafted examples like
>>
>> https://github.com/m3db/m3x/blob/master/unsafe/string.go#L62
>>
>> just become the right way to do it.
>>
>> Until then maybe we should just rely on the structural similarities 
>> between the two types and cast between them. This seems especially 
>> appealing as Jan pointed out above that at least one of the hypothetical 
>> problems isn't hypothetical at all.
>>
>>
>> On Monday, 23 September 2019 12:43:34 UTC+2, kortschak wrote:
>>>
>>> Any particular reason for that? Neither is safer than the other and 
>>> it's not clear to me that you can actually achieve the goal of having a 
>>> compile-time check for the correctness of this type of conversion. 
>>>
>>> On Mon, 2019-09-23 at 02:36 -0700, fra...@adeven.com wrote: 
>>> > But this relies on a string's representation being the same as, but a 
>>> > bit smaller thabn, a []byte. I would prefer to use 
>>> > the Slice/StringHeader. 
>>>
>>> -- 
>> 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 golan...@googlegroups.com.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/golang-nuts/422ca2bd-d6c8-4ebe-9578-8dd3cd8317e9%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/golang-nuts/422ca2bd-d6c8-4ebe-9578-8dd3cd8317e9%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>>

-- 
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/00bdea81-4a2e-45ab-9775-c398cbea7e2a%40googlegroups.com.

Reply via email to