With pointers, they are in the heap, but at least there is no overhead. You could also declare them embedded (without the *s), but then the Sum struct would have a size that is a sum of all the variants' sizes, instead of a proper union which should have the max size (more or less).
type Sum struct {
type SumChoice
A Avariant
B Bvariant
}
This is what I meant by saying that it depends on exactly what you mean by "sum types".
Got it. Although I’m not sure what “no overhead” means if the instances have to live way far away on the heap. That means you’ve got an alloc (including a mutex lock), then the value lives far away, then the garbage-collection overhead then the delete. When I think sum-type I think a flag plus storage for the maximum size and alignment type, and all of the above bookkeeping and cache misses go away.
Yes, you're right - I was thinking of "no space overhead", and even that is not entirely correct (you pay an extra pointer per variant size, which in this case would be some overhead over the embedded version).
Still, I think most people don't worry so much about efficient packing of sum types, and instead the safety and convenience factors are more important. Of course, YMMV based on exact usage.
I'm not in anyway claiming that Go supports sum types. Someone just asked how they may be emulated, and I don't think it should be surprising that emulation has an overhead.