Hacker News new | ask | show | jobs
by siebenmann 567 days ago
Interfaces aren't bit-packed and they force storing all values as a separate allocation that the interface contains a pointer to (escape analysis may allow this separate value to be on the stack, along with the interface itself). I believe that Go used to have an optimization where values that fit in a pointer were stored directly in the interface value, but abandoned it, perhaps partly because of the GC 'is it a pointer or not' issue. In my view, some of what people want union types for is exactly efficient bit-packing that uses little or no additional storage, and they'd be unhappy with a 'union values are just interface values' implementation.

(I'm the author of the linked to article.)

1 comments

A separate allocation is not forced. The implementation could allocate a block of memory large enough to hold the two pointers for the interface value together with the largest of the types that implements the interface. (You can't do that with an open interface because there's no upper bound, but the idea here is to let you define closed interfaces.)

In cases where there is a lot of variance in the size of the different interface implementations, separate allocations could actually be more memory efficient than a tagged union. In any case, I'm not sure that memory efficiency is the main reason that people miss Rust-style enums in Go.

The problem with allocating bit-packed storage is that then you are into the issue where types don't agree on where any pointers are. Interface values solve this today because they are always mono-typed (an interface value always stores two pointers), so the runtime is never forced to know the current pointer-containing shape of a specific interface value. And the values that interface values 'contain' are also always a fixed type, so they can be allocated and maintained with existing GC mechanisms (including special allocation pools for objects without pointers and etc etc).

I agree with you about the overall motivation for Rust-style enums. I just think it's surprisingly complex to get even the memory efficiency advantages, never mind anything more ambitious.

> The problem with allocating bit-packed storage is that then you are into the issue where types don't agree on where any pointers are.

The solution to this should be trivial. You just have to extend the gcshape concept to account for the enum discriminator.

The bigger problem is mutability. Any pointers into the bit-packed enum storage become invalid as soon as you change its type. To solve this you can either prohibit pointers into bit-packed enum storage, which is very limiting, or introduce immutability into the language. Immutability is particularly difficult to add to go, where default zero-values emerge in unexpected places (such as the spare capacity of slices and the default state of named return values)
I was saying that you can have a single allocation without using bit packing.

I'm not sure what you're referring to with 'anything more ambitious'.