I found this trick recently to replicate a C union in Go with 
unsafe.Sizeof, arrays, and some constant arithmetic. This lets you 
stack-allocate data that needs to be the max size of multiple other data 
types. So given a type A and B that you want to union, you can say

const ASize = int64(unsafe.Sizeof(*new(A)))
const BSize = int64(unsafe.Sizeof(*new(B)))
const diff = ASize - BSize
const max = ASize - ((diff>>(bits.UintSize-1))&1)*diff

var storage [max]byte
*(*A)(unsafe.Pointer(&storage))
*(*B)(unsafe.Pointer(&storage))

This process can be repeated for any number of types. For example, if you 
wanted to represent a tagged union defined like

type A =
    | B
    | C int
    | D (a: int, b: int)

you could lower it to something like

const size = int64(unsafe.Sizeof(*new(B)))
const size0 = int64(unsafe.Sizeof(*new(C)))
const diff = size - size0
const max = size - diff*((diff>>(bits.UintSize-1))&1)
const size1 = int64(unsafe.Sizeof(*new(D)))
const diff0 = size1 - max
const max0 = size1 - diff0*((diff0>>(bits.UintSize-1))&1)

type A struct {
        tag     uint8
        storage [max0]byte
}
type B struct{}
type C int
type D struct {
        a int
        b int
}

Unfortunately, the resulting code is pretty inefficient compared to 
interfaces or struct embedding. It might be that the use of unsafe is 
hindering compiler optimizations, or maybe it's an alignment issue.

-- 
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/5d150c6a-3ecb-4cb8-91b3-c048940294aen%40googlegroups.com.

Reply via email to