Stream: beginners

Topic: How does Boxing and Unboxing work in Roc


view this post on Zulip Luke Boswell (Oct 24 2022 at 09:22):

Help wanted I would really appreciate if someone could check my explanations for Box and Unbox. This is the best I could come up with based on digging through the implementation and google.

## Allocate a value on the heap. Boxing is an expensive processes as it copies
## the value from the stack to the heap.
##
## expect Box.unbox(Box.box "Stack Faster") == "Stack Faster"
box : a -> Box a

## Return a value to the stack. Unboxing is an expensive processes as it copies
## the value from the heap to the stack.
##
## expect Box.unbox(Box.box "Stack Faster") == "Stack Faster"
unbox : Box a -> a

view this post on Zulip Ayaz Hafiz (Oct 24 2022 at 13:16):

Yes, that’s correct, but “unbox” only “returns a value” in the sense that it will return a copy of the boxed value; it won’t destroy the box. The upside of using a Box is that sometimes you might have very large values that cost more to copy around the stack (because they must be copied on the stack to be passed between functions, for example) than it is to allocate them on the stack and only copy around the pointer to their memory address.

The actual cost of allocation depends on the underlying allocator, it might actually be very cheap, but those are details that aren’t important for understanding Box.

view this post on Zulip Brian Carroll (Oct 24 2022 at 13:21):

It seems a bit wrong to say it's slow because of the copying. I wouldn't really expect that to be a big part of the cost, though I'm not the most knowledgeable about that. Isn't it more the allocation itself, and any reference counting you might need from that point on in the program?

view this post on Zulip Brian Carroll (Oct 24 2022 at 13:21):

(Also "an expensive processes" is a typo. It mixes singular and plural.)

view this post on Zulip Folkert de Vries (Oct 24 2022 at 13:36):

it's a level of indirection, and that has upsides and downsides. This should be a "don't do it if you aren't sure you need it" sort of thing

view this post on Zulip Folkert de Vries (Oct 24 2022 at 13:37):

it exists for interaction with platforms, and in general to get a quick copy of big values: rather than copying all the bytes of the value, you just bump the RC and done. But that only makes sense if the value in question is truly big

view this post on Zulip Richard Feldman (Oct 24 2022 at 14:58):

oh I actually thought the main use would be to prevent tag union variant sizes from exploding :big_smile:

view this post on Zulip Richard Feldman (Oct 24 2022 at 14:58):

e.g. boxing one big variant, or a closure

view this post on Zulip Richard Feldman (Oct 24 2022 at 14:59):

I think mentioning those use cases in the Box docs would be a good idea, as would mentioning that you only ever need to use Box as a performance optimization, and by default it makes performance worse, so you should only use it under very specific circumstances!

view this post on Zulip Brendan Hansknecht (Oct 24 2022 at 15:00):

Performance optimization or if the platform requires it as in the case of having state of unknown type passed to the platform. Required for TEA.

view this post on Zulip Luke Boswell (Oct 25 2022 at 06:19):

Updated to the following. Does this look better?

## Allocate a value on the heap. Boxing is an expensive process as it copies
## the value from the stack to the heap. This may provide a performance
## optimization for advanced use cases with large values. A platform may require
## that some values are boxed.
##
## expect Box.unbox(Box.box "Stack Faster") == "Stack Faster"
box : a -> Box a

## Returns a boxed value.
##
## expect Box.unbox(Box.box "Stack Faster") == "Stack Faster"
unbox : Box a -> a

view this post on Zulip Brian Carroll (Oct 25 2022 at 06:39):

I actually just don't agree with the point about it being expensive due to copying and I think it would be better to remove that. Roc is an immutable language. We do copying in all sorts of other operations and we don't call it expensive anywhere else. So I don't like making it into a big deal for this one case where the copying is not particularly special.

view this post on Zulip Brian Carroll (Oct 25 2022 at 06:40):

It's ok to say it copies from stack to heap, but highlighting that as unusually expensive is incorrect IMO


Last updated: Jul 05 2025 at 12:14 UTC