Stream: ideas

Topic: Explicit Panic in Roc


view this post on Zulip Brendan Hansknecht (Mar 14 2022 at 02:55):

So I know that in general, Roc has decided not to have an explicit panic. I think that maybe this should be reconsidered.

As I have been working on a Dict implementation in Roc, I have had many cases where I have wanted to panic due to impossible states. For example, If I ever get an Err OutOfBounds in any functions in the dictionary, that is definitely a bug and I want to know about it. It should not be possible. Without panic, I have to decide what to do when I receive an Err OutOfBounds. I could sneakily force a panice with 0 - 1 leading to a really confusing error message. I could just return some form of default value. But if someone calls Dict.insert and I return the old dictionary, it makes no sense. I think that panic is important for finding bugs and representing potentially impossible states that the compiler is not smart enough to optimize away.

On top of that, messing around with panics can be a way to get llvm to do more optimizations. If every operation produces the same potential panic, they will potentially be able to be checked together and produce one check and jump instead of many. This is one of the things I had to fight with a lot when trying to get hot loop to run faster by merging jumps.

view this post on Zulip Richard Feldman (Mar 14 2022 at 03:06):

I feel torn on this topic. I'm open to it, but it's definitely a one-way street; once it's in the language, there's no going back. :sweat_smile:

view this post on Zulip Richard Feldman (Mar 14 2022 at 03:07):

if I'd never used Rust, I don't think I'd be open to it. But Rust is an interesting example of an ecosystem where culturally panic seems to be used sparingly in libraries, such that I don't really worry about libraries panicking on me when they shouldn't, and I can't remember really feeling burned by that in practice.

view this post on Zulip Richard Feldman (Mar 14 2022 at 03:13):

the biggest reasons I'm open to it:

  1. If it turns out it can unlock more performance optimizations, e.g. via LLVM. (I'm actually somewhat skeptical that it can, but maybe there's a way!)
  2. If hosts can extract stack traces from them (which is theoretically possible, but that feature would be a whole project), then in cases where you're not planning to do any graceful error recovery anyway because you think the situation should never happen, then if platforms provide application authors with some sort of way to specify error reporting when a panic happens, then (e.g. in a server application) it can send an actual stack trace back to the developers - which could help more effectively track down bugs.

view this post on Zulip Richard Feldman (Mar 14 2022 at 03:15):

I think we want to support that #2 situation someday anyway, because if my server pancs on an integer overflow, it would be awesome if I got a stack trace so I could see where in the code the panic actually happened...but without that stack trace, getting an automated report of "an integer overflowed somewhere in your gazillion lines of code" is not likely to lead that bug to get fixed ever :sweat_smile:

view this post on Zulip Richard Feldman (Mar 14 2022 at 03:15):

I'd love to hear anyone's thoughts on this!

view this post on Zulip Ayaz Hafiz (Mar 14 2022 at 04:09):

I think there is a big developer experience aspect to this. Having a good story around irrecoverable errors and how to use them hygienically is important. If the answer is "there is no language-level way to have irrecoverable errors", I think folks will just end up creating their own ad-hoc versions like Brendan's 0 - 1, which has poor ergonomics from a code-reading and error-reporting point of view. Even programs that propagate errors all the way up may reasonably use ad-hoc panics for cases where the compiler is not smart enough to understand their control flow (for example in redundant branches, see #ideas > Narrowing types in when expressions, or something like compiling a regex you know is infallible).

Anecdotally, I have seen some classes where it makes more sense to panic than it does to propagate errors up:

  1. When your domain logic includes invariants that are cumbersome or otherwise not useful to express via the type system. There are many of these in the Roc compiler codebase itself (e.g. this string starts with an uppercase letter, this vector is non-empty, this built-in definitely exists in a map, etc). Here it makes sense to panic because you want to know loudly when your invariants are broken, and you don't have a meaningful way to recover from a broken invariant because you expect it to be, well, invariant.
  2. When you don't have a good way to recover, and shouldn't expect anyone up the call stack to have a way to recover either. For example suppose you were doing some writes on a NFS or some other network and then all of a sudden you get partitioned. At this point you know something is wrong, but you may not have a good way to clean up, and at worse your (or your callers') clean up attempts may induce further corruption. At this point you want to fail loudly, sending off sirens and get eyes on the error rather than passing it up.
  3. When you're prototyping something, or writing tests, or trying to add a feature incrementally. During this kind of development and in non-production code, it's unpleasant when the compiler blocks your progress because it'd like you to handle all cases, which may not be your priority.

view this post on Zulip Ayaz Hafiz (Mar 14 2022 at 04:11):

I think there is space for both errors-as-values and irrecoverable panics. They solve different problems. There is the problem of "please don't replace your valued errors with panics (and vice versa)", but there is merit to both uses.

view this post on Zulip Brendan Hansknecht (Mar 14 2022 at 04:16):

I think it is important that panic in Roc does not have a way to get caught. It should be an unrecoverable exception based on when an invariant is broken. Something that can only be dealt with by the platform, if at all. I think that if someone ever wants to catch a panic, the panic shouldn't exist at all.

view this post on Zulip Brendan Hansknecht (Mar 14 2022 at 04:16):

Hopefully will be a clear indication of a bug.

view this post on Zulip Brendan Hansknecht (Mar 14 2022 at 04:21):

If it turns out it can unlock more performance optimizations, e.g. via LLVM. (I'm actually somewhat skeptical that it can, but maybe there's a way!)

I am pretty sure that I can prove this true. One simple case: Make every operation that might panic (but you can guarantee never will) use the checked version of the operation. Make them all throw the same "unreachable" panic when the check fails. Now they all will be jumping to the exact same code block if they panic.

This enables llvm to merge the checks together if one check guarantees another one of the checks. llvm can't do that merging if the 2 operations lead to different kinds of panics.

This is one of the things I have run into with incrementing integers and using them to access a list. I know that neither will ever overflow or access out of bounds. If they both threw the same panic, they could be merged into one check. They don't so I always have at least 2 checks.

view this post on Zulip Kevin Gillette (Mar 14 2022 at 06:34):

I agree that there should at least be a consistent story for this in Roc. If it has panics at all, then we're already well along that one-way street, and the only way to truly reverse direction is to remove the concept of panics entirely (instead favoring checked, wrapping, or other deterministic outcomes). I agree that panics, when they do exist, should be irrecoverable but stylistically used only to check invariants/impossible states. Some languages have pre-condition/post-condition clauses in functions that formalize panics into rather declarative, concise, and readable assertions (essentially a constraint language within the grammar); I don't know how well that'd fit the panics that Roc already has, but it could handily solve Brendan's needs, for example, without obfuscating the code by mixing invariant checks with semantic behaviors.

It's worth noting that pre-conditions should not be used to validate untrusted inputs, since Roc's type system is expressive enough, particularly with tags, to handle almost all such validation in a cleaner way. The pre-condition, however, would be used to validate the internal state managed by the module itself (i.e. of the Dict input); it may be possible that all pre-conditions could be represented as post-conditions instead, since if a module has encapsulated internal state, then only the module's functions can produce such values, thus state could be eagerly checked at the end of a function doing updates rather than lazily at the start of a function receiving the updated value. It's probably then also the case that these invariants could be expressed alongside the type definition itself instead of within functions (perhaps as an assume clause, similar to how where is proposed in #Abilities). Perhaps modules could have a formal bug-report destination concept which Roc could use to automatically provide the option to, after review, submit a report/issue upon detected issue. Presumably productionized/optimized builds would simply omit code that checks the invariants.

view this post on Zulip Derek Gustafson (Mar 14 2022 at 11:20):

@Kevin Gillette Worth noting that currently the panics are in the compiler, either to verify invariants, like Ayaz described, or as TODOs where a feature needs to be added. None of these should be viewable to Roc users, once it's production ready

view this post on Zulip Kevin Gillette (Mar 14 2022 at 14:50):

@Derek Gustafson I had thought there were user-visible panics in the language itself, such as for numeric operations that overflow.

view this post on Zulip Derek Gustafson (Mar 14 2022 at 15:03):

I had missed that

view this post on Zulip Brendan Hansknecht (Mar 14 2022 at 15:31):

Yeah, you can always generate a panic using integer over or underflow. In my case, I just set the dictionaries size to 0 - 1 which cause it to underflow

view this post on Zulip Zeljko Nesic (Mar 14 2022 at 18:16):

Haskell does this very nice from the ergonomics perspective.
They don't panic, they specify undefined behavior.

view this post on Zulip Zeljko Nesic (Mar 14 2022 at 18:16):

undefined type checks everytime

view this post on Zulip Zeljko Nesic (Mar 14 2022 at 18:17):

Maybe we can have whatever

view this post on Zulip Folkert de Vries (Mar 14 2022 at 18:20):

undefined isn't as nice from a reporting perspective

view this post on Zulip Zeljko Nesic (Mar 14 2022 at 18:20):

It really helps as much as Debug.todo helps for sketching the code , but I think that we should not panic in any way.

view this post on Zulip Folkert de Vries (Mar 14 2022 at 18:20):

I like rust's unreachable

view this post on Zulip Zeljko Nesic (Mar 14 2022 at 18:21):

Well, I've written it with a wrapper that prints a message before ~undefining~.

view this post on Zulip Brendan Hansknecht (Mar 14 2022 at 18:32):

I also like unreachable because it is clearer about when it should be used.

view this post on Zulip Brendan Hansknecht (Mar 14 2022 at 18:33):

It really helps as much as Debug.todo helps for sketching the code , but I think that we should not panic in any way.

How is undefined different from a panic? What happens if it is reached? Does it just keep executing and hope nothing is wrong?

view this post on Zulip Folkert de Vries (Mar 14 2022 at 18:35):

for sketching we have holes, the single _ character

view this post on Zulip Folkert de Vries (Mar 14 2022 at 18:35):

much more convenient to type

view this post on Zulip Richard Feldman (Mar 14 2022 at 19:35):

undefined type checks everytime

so does panic! in Rust, and so would any kind of explicit panic in Roc

view this post on Zulip Richard Feldman (Mar 14 2022 at 19:58):

one thing that I think is fairly compelling is that if something fits all of these criteria:

...then panicking (when the application author is able to specify how to recover and explain what happened to the user) is arguably better than using something like Result for several reasons:

of course, the temptation of having an explicit panic available is that, because it's more convenient in those scenarios, to choose to bail out and show the user an error more often - even in scenarios where if Result was the only option, you'd otherwise handle the error more gracefully than that

view this post on Zulip Folkert de Vries (Mar 14 2022 at 20:13):

here i'm hopeful that our editor could make the Result approach easier

view this post on Zulip Folkert de Vries (Mar 14 2022 at 20:13):

as in, "i want to make this function return a result, bubble that up to all call sites"

view this post on Zulip Richard Feldman (Mar 14 2022 at 20:33):

definitely! Although it still makes all the types more involved along the way

view this post on Zulip Richard Feldman (Mar 14 2022 at 23:57):

another thing to consider: the current design for panics in Roc is heavily performance-optimized for the case where they never happen.

A panic in a Roc application literally runs a function in the host called roc_panic and that's it. It's completely up to the host what that code does.

This will usually happen in the middle of a call stack. The host can unwind that stack using libunwind, but has no way to clean up all the heap memory that was in use.

view this post on Zulip Richard Feldman (Mar 14 2022 at 23:59):

So the only way today to avoid a memory leak on every panic is to have roc_alloc remember all the virtual memory pages where it was stored, deep clone the entire application state into a fresh virtual memory page, and release all the old ones back to the OS.

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:00):

This is actually theoretically very efficient if you're a server, because everything is arena allocated anyway, so you just fire off a HTTP 500 response and throw away the arena

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:01):

But for something like a GUI, a panic would actually result in cloning the entire application state, which would likely at least drop a couple of frames

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:03):

(There's a theoretical way to get panics to walk the stack and decrement refcounts but it would be a huge, messy project and I'd prefer not to do it.)

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:05):

Dropping a couple of frames on panic is honestly probably fine if they are extremely rare events, like actual "I thought this would never ever happen" things - integer overflows and such - but I think a valid concern is that explicit recoverable panics might result in people overusing them for coarse-grained control flow and ending up with slower and slower programs as their application state grows, and then spreading the word that "Roc is slow at scale, actually."

view this post on Zulip Ayaz Hafiz (Mar 15 2022 at 00:06):

If the host halts the process when a panic happens though that's not an issue. I can't think of many examples other than a server-like process when a host would want to do something other than exit?

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:07):

well in a UI application you'd probably want to let the user continue with what they were doing

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:08):

like the operation they just attempted failed catastrophically, so you display an error, but then they should be able to press ok and try something else

view this post on Zulip Brendan Hansknecht (Mar 15 2022 at 00:10):

Idk

view this post on Zulip Brendan Hansknecht (Mar 15 2022 at 00:10):

If it failed with a panic, continuing probably doesn't make sense

view this post on Zulip Brendan Hansknecht (Mar 15 2022 at 00:10):

If they failed with an error, continuing makes sense.

view this post on Zulip Ayaz Hafiz (Mar 15 2022 at 00:10):

hm.. personally, it seems to me like that kind of pattern means errors should be used and not panics. In my mind the role of panics is entirely different than that of errors, and panics should only be used when there's literally no way to recover. If you can present an error and keep going you should send an error up

view this post on Zulip Brendan Hansknecht (Mar 15 2022 at 00:10):

:point_up: That

view this post on Zulip Brendan Hansknecht (Mar 15 2022 at 00:11):

Otherwise, there is no way for the host to know if the application is even in a usable state. The model may be total garbage is half changed to the new state.

view this post on Zulip Folkert de Vries (Mar 15 2022 at 00:11):

e.g. so far I've not seen a rust panic being caught

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:11):

that's a fair point

view this post on Zulip Ayaz Hafiz (Mar 15 2022 at 00:11):

but I think a valid concern is that explicit recoverable panics might result in people overusing them for coarse-grained control flow but I think a valid concern is that explicit recoverable panics might result in people overusing them for coarse-grained control flow

I guess this is the meat of the problem right, how do you enforce that panics and errors are used for orthogonal reasons.. maybe there is a way to make it harder to use panics for error handling

view this post on Zulip Folkert de Vries (Mar 15 2022 at 00:11):

I know it's possible, I just don't think it really happens in the wild

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:12):

yeah

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:12):

so, maybe that should be a big cultural thing then

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:13):

panic should mean unrecoverable loss of state

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:13):

so if a panic happens, what you're supposed to do is exit immediately, possibly after logging diagnostic info about what went wrong

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:14):

should we call it something else then?

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:14):

e.g. crash

view this post on Zulip Ayaz Hafiz (Mar 15 2022 at 00:14):

Folkert de Vries said:

I know it's possible, I just don't think it really happens in the wild

(aside: rustc uses it to convert panics into errors :face_with_thermometer: )

view this post on Zulip Brendan Hansknecht (Mar 15 2022 at 00:14):

could even go with unrecoverableError just to make it stick out and be long to type.

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

Would make things pretty clear.

view this post on Zulip Brendan Hansknecht (Mar 15 2022 at 00:17):

From the platform perspective an unrecoverable application error may not always mean an unrecoverable platform error. So I think this all makes sense. It means consider any application state and memory as garbage, but feel free to continue if that doesn't matter to the platform/the platform knows how to reset.

view this post on Zulip Kevin Gillette (Mar 15 2022 at 00:44):

I'm fine with panic meaning unrecoverable, particularly if, in practice, the host can know how to deallocate everything related to Roc, in case Roc is used in an embedded way.

Panic will get misused if it's recoverable within Roc itself. If unrecoverable, it should only be used for programmer mistakes

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:51):

in Elm it was called crash back when it was allowed outside release builds (which it no longer is), and that was how people used it

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:51):

crash was responsible for NoRedInk's one instance of having a production runtime exception in 7 years, so I guess that's not a bad track record :laughing:

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:53):

Panic will get misused if it's recoverable within Roc itself. If unrecoverable, it should only be used for programmer mistakes

unfortunately there's no real way to prevent this

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:54):

a platform author can always have the application author provide a function to run if a crash happens, and then have the host call that function from within roc_panic

view this post on Zulip Richard Feldman (Mar 15 2022 at 00:54):

there's no way to rule it out, since hosts can call whatever functions they like

view this post on Zulip Kevin Gillette (Mar 15 2022 at 03:35):

Richard Feldman said:

a platform author can always have the application author provide a function to run if a crash happens, and then have the host call that function from within roc_panic

Sure, but that's categorically different than a recovery feature provided by and within the language itself.

view this post on Zulip Brendan Hansknecht (Mar 15 2022 at 04:05):

As a general question, was anyone ever suggesting adding a recovery feature into roc itself? I am only try to get some sort of user exposed panic feature. No want for recovery.

view this post on Zulip jan kili (Mar 15 2022 at 04:42):

The only time so far that I've wanted a Roc panic/crash was to assert the safety of literals (which I think qualifies as catching "programmer mistakes" as mentioned above).

» x = 5
… x % 3

Ok 2 : Result (Int *) [ DivByZero ]*

» x = 5
… x % 3 |> Result.withDefault 666 # No need for error handling, so let's just get use the Ok value. However, this is smelly.

2 : Int *

» x = 5
… modSafe = \a, b ->
…     a % b |> Result.withDefault 666 # Encapsulate the smelliness into a helper function.
… modSafe x 3

2 : Int *

» x = 5
… modSafe = \a, b ->
…     when a % b is
…         Ok c -> c
…         DivByZero -> crash "modSafe doesn't support b=0!" # Is this less smelly? I don't know!
… modSafe x 3

However, I can see this use case increasing flakiness. :shrug:

view this post on Zulip Martin Stewart (Mar 15 2022 at 09:55):

Richard Feldman said:

so if a panic happens, what you're supposed to do is exit immediately, possibly after logging diagnostic info about what went wrong

What about if you're running 3rd party Roc code? For example, plugins in an editor. That shouldn't bring down the whole editor.

Edit: It occurred to me that you're probably talking about just the Roc code, not the platform, so nevermind.

view this post on Zulip Kevin Gillette (Mar 15 2022 at 13:36):

Perhaps Roc packages, once there's a package manager, can be automatically annotated with whether they panic, and maybe even distinguishing between panics for data they control (as in Dict example elsewhere, counter-balanced by test coverage) vs parameters you can pass in (such as panicking if you pass an even number). That could be used by users in search of a package to evaluate their reliability.

view this post on Zulip Kevin Gillette (Mar 15 2022 at 13:46):

Ideally most explicit panics would be for a module's own types.

I could however see some cases where the function must only handle numbers of a certain range. For "must be non-negative" an unsigned type could be required, but occasionally there are stranger ranges ("between 3 and 127"). Some languages have ranged number types, but those haven't proved so valuable to have ended up in many languages. For Roc, the function could return a Result, or take an opaque type that would've been produced by another function returning a Result, or it could panic. I suspect panic would be quite disfavored here, but I also don't know in practice when too much use of Result or opaque types gets tedious.

view this post on Zulip Kevin Gillette (Apr 10 2022 at 20:27):

While roc_panic does seem straightforward and reasonable for many platforms (where the host is just there to serve the Roc application), it seems plausible that there are some platforms in which roc_panic, at least afaict, doesn't provide great choices:

  1. Consider an pre-existing game engine (such as Unity or Godot) adapted to run Roc for game-specific code, probably in the form of behavioral hooks. A roc_panic probably shouldn't exit the game, nor should it no-op, since that would be undefined behavior and memory leaks; perhaps the character whose behavior panicked would just fall back to some non-custom behavior (alongside reporting the issue).
  2. Consider a productionized web-server platform in which an organization has decided that issues in, perhaps, one corner case of one endpoint/handler should not crash the whole service: likewise, a direct roc_panic call is not very convenient.
  3. Consider some case in which live code compilation/loading is used to allow untrusted users run Roc code, similar to Web-Assembly or PNACL can work with safety/conformance scanning (to which Roc could be naturally well suited, being side-effect-free). Restrictions would probably be to run code in a separate thread with a limited size for stack and allocations, and is pre-empted after a certain time or otherwise proven to be a "total" function with a linear-ish time bound. In such a case, panics should be expected, and it would certainly be undesirable for these to cause leaks or exit the program.

All of these above examples feel less like a host <-> tenant relationship (where the Roc application has some expectation of exclusivity or prime importance), but instead more like a host <-> guest relationship (where this particular Roc code fits more into the role of a embedded scripting component, albeit faster and uninterpreted). Other terms certainly could be application (as is already used) and behavior.

These certainly may be misconceptions, but the [solvable] issues I see here with roc_panic are:

Certainly a few of workarounds for memory leaks are for a host to give a separate arena to each thread/invocation, or to manually unwind the stack to find heap references (needing to know a lot of unsafe details about Roc in the process, and hoping its calling convention never changes).

I wonder if we could guarantee that, following a roc_panic in which the host does not call exit, Roc would unwind its own stack and decrement/free allocations, finally resulting in a sentinel "I panicked" value to the host. Roc could accept from the host a pointer to a signal variable (somewhat like errno) that it might overwrite before the Roc code returns control to the host. Alternatively, Roc could provide some utility functions to host that could be called within roc_panic, such as a function for filling a host-provided buffer with a formatted stack trace, and a function for unwinding the stack.

It seems like, ideally, hosts should need to know very little about Roc, and Roc should be able to clean up its own allocations even in the case of a panic (as it cleans allocations when no panics have occurred).

view this post on Zulip Ayaz Hafiz (Apr 10 2022 at 21:27):

there were related discussions about this in https://roc.zulipchat.com/#narrow/stream/304641-ideas/topic/Explicit.20Panic.20in.20Roc

view this post on Zulip Kevin Gillette (Apr 10 2022 at 22:50):

Ayaz Hafiz Thanks for the reminder!

Richard Feldman said:

(There's a theoretical way to get panics to walk the stack and decrement refcounts but it would be a huge, messy project and I'd prefer not to do it.)

Why would it be a huge mess? It seems like we could just arrange for each Roc stack frame to have heap-references at the "end" of the frame, along with an integer indicating the number of such references. At that point wouldn't the stack just be essentially a [contiguously-allocated] linked-list of frames, where the allocation-relevant parts, and the info needed to unwind, are all self-describing and size-agnostic? It might be a deep change, and there are probably some technical road-blocks, but, granted coming from someone with no specific experience in this area, it does not sound particularly intensive from an algorithmic sense.

view this post on Zulip Richard Feldman (Apr 11 2022 at 00:23):

so libunwind has a system like this, and LLVM is aware of it and can emit this info

view this post on Zulip Richard Feldman (Apr 11 2022 at 00:25):

I got a "hello world" example with clang and libunwind working some time ago, where it's at least able to walk the stack and print out the function calls

view this post on Zulip Richard Feldman (Apr 11 2022 at 00:26):

however, libunwind just lets you unwind the stack, it doesn't really ship with a way to say "okay at each point in the stack, here's some extra info that you need to know about how to clean up heap stuff for this stack frame"

view this post on Zulip Richard Feldman (Apr 11 2022 at 00:26):

C++ exceptions let you do that, and LLVM knows how to emit those too

view this post on Zulip Richard Feldman (Apr 11 2022 at 00:26):

in fact, we used to do this for panics in Roc

view this post on Zulip Richard Feldman (Apr 11 2022 at 00:39):

it was very complicated and caused all sorts of problems, including:

view this post on Zulip Kevin Gillette (Apr 11 2022 at 01:28):

Thanks for the context!

I didn't realize that made that many assumptions about calling conventions and stack layout, but it makes sense in retrospect that it would.

Linking against libc++ for just this reason certainly doesn't seem like a win.

In theory, how hard would it be for Roc to provide its own arena allocation implementation? iow, Roc still calls roc_alloc, but instead of asking for 4 bytes here or 32 bytes there, it just asks for page-size multiples. At that point it'd be a bit simpler for arbitrary platforms to ask Roc, as part of a roc_panic, to free the arena pages (presumably part of the first page could hold accounting that links to another pages).

This would still leave the question of reference data shared across the host <-> Roc boundary, but at least for hosts in which that's not a concern (such as with static data or where the counts can be reset back to 1), this would give arbitrary hosts a non-leaking recovery path.

view this post on Zulip Richard Feldman (Apr 11 2022 at 12:50):

hm, what would the benefit be of that compared to status quo? Hosts can already choose to have roc_alloc calls do arena allocation, and then the host knows all about the allocated memory and can deallocate as necessary

view this post on Zulip Kevin Gillette (Apr 11 2022 at 18:13):

I'm suspect that providing an arena allocator is more work than many host authors (including those who want a recovery option) will want to spend time/complexity investing.

While some host languages no doubt will have an easier time of this than others, it's probably not a differentiating feature for many platforms, and thus leaves a poorer tradeoff for a host author that wants recovery, but doesn't have great arena allocation implementations in their language, or when there are options but the host author doesn't want to research them (dilemma of choice).

If Rust or Zig have good options (performant and robust), presumably we could provide that as an option to host authors via some pragma or build option. We wouldn't need to implement our own arena allocator, but merely layer a good preexisting one atop roc_alloc at the host author's request.

view this post on Zulip Brendan Hansknecht (Apr 11 2022 at 18:52):

It should just be importing a rust library for the most part. I feel most of the basic roc_* functions could be implemented in a library

view this post on Zulip Brendan Hansknecht (Apr 11 2022 at 18:53):

I think this can be supported rather simply on the platform side with a minor ecosystem. So using rust/zig/etc package manager instead of building it into roc

view this post on Zulip Brendan Hansknecht (Apr 11 2022 at 18:57):

I'm suspect that providing an arena allocator is more work than many host authors (including those who want a recovery option) will want to spend time/complexity investing.

I think that this is a bad assumption based on the vision of Roc. Most roc users will not be platform authors. Platform authors, especially those implementing core platforms that many people depend on will need to deal with low level implementation details. This is not something most people have to think about at all, but some people do.


Last updated: Jun 16 2026 at 16:19 UTC