The feature in OxCaml that more languages should steal
https://theconsensus.dev/p/2026/06/27/the-feature-in-oxcaml-more-languages-should-steal.html
tosh · 5 days ago
4 comments
https://theconsensus.dev/p/2026/06/27/the-feature-in-oxcaml-more-languages-should-steal.html
tosh · 5 days ago
4 comments
Georgelemental · 5 days ago
> In most languages (Java, Go, C#, Rust, Zig, OCaml, etc.) the process is reversed: you take a profiler to try and find allocations (usually in loops that happen millions of times). Then you go and eliminate or minimize the allocations.
This isn't fully correct. In Zig, the common pattern is that any function which allocates accepts an explicit allocator parameter; if you don't pass one explicitly, you don't get any heap allocations.
Rust doesn't make things quite that visible. But, if you restrict yourself to the standard library and crates designed with this in mind, allocations are usually not too hard to find. And you can always use `#![no_std]` without `alloc` if you want to be sure. Neither language is ever going to insert a heap allocation if it's not somewhere in the source.
scritty-dev · 5 days ago
could you clarify for me, because isn't that a different guarantee? from my understanding, Rust and Zig make allocations explicit, but [@zero_alloc] lets you declare "this function (and everything it calls) must not allocate" and have compiler enforce it.
eatonphil · 5 days ago
They are indeed different. In Zig you might get the allocator via a struct field or just via importing the global allocator.
const std = @import("std");
fn makeBuffer(n: usize) ![]u8 {
return std.heap.page_allocator.alloc(u8, n);
}
Here are a few examples from the last release of Bun before the rewrite into Rust.https://github.com/oven-sh/bun/blob/bun-v1.3.14/src/install/...
https://github.com/oven-sh/bun/blob/bun-v1.3.14/src/shell_pa...
The allocator via function parameter is only a convention and only even one convention. It is certainly a strong convention (throughout the standard library anyway) but it is just a convention.
Recent Rust also has the ability to pass allocators but that's the same thing. And even if you use no_std in Rust you might call into some other library's no_std function that allocates and you wouldn't be able to grep for that.
wmedrano · 5 days ago
If you don't pass an allocator param in Zig, then the function basically can't allocate.
3836293648 · 4 days ago
No, that's just a convention. Any function can just create a new allocator, or import the global one, or use malloc from libc. Zig does nothing to enforce this convention.
scritty-dev · 3 days ago
isn't that more of a convention than an actual guarantee?
3836293648 · 5 days ago
That's just not true. It's just a convention. You can assign the allocator to a global or use malloc from libc. The article is correct.
xg15 · 5 days ago
Can we extend this to more properties, such as: Does IO, makes system calls, launches or interacts with threads, may block or has an unexpected space/time complexity?
pjmlp · 5 days ago
Kind of, via effects, which is yet another way to use the type system to enforce specific kinds of execution flows.
pjmlp · 5 days ago
Managed languages already had explicit stack allocation during the last century.
Unfortunately we went crazy with heap only types, on the other hand thankfully the pendulum is turning around and most compiled languages are having them back.
However nothing of this matters if you end up shipping the app inside Electron.
lioeters · 4 days ago
This is one of those language features that you can't unsee after you learn about it. In hindsight it feels like it should have been common sense, like avoiding or preventing global variables, GOTO statements, mutable state, etc. And usually you start noticing that good software developers have already been practicing it by instinct.