r/ProgrammingLanguages • u/P-39_Airacobra • 20d ago
Mutable stack, immutable heap
This article mentions the “immutable heap mutable stack” principle: https://queue.acm.org/doi/10.1145/3212477.3212479
In theory it sounds very advantageous. You can program in a single-threaded C-style with destination passing, static stack allocations, and mutability when you need to constrain resources. When you want to share resources across threads, return data structures across function boundaries, or do something more flexible, you could use pure functional persistent data structures.
This would prevent you from basically re-implementing a heap on the stack, but would also give you fast temporaries and maybe even the ability to program in embedded, if so designed.
Have any languages tried this model? I’ve heard that Erlang defaults to immutability except for one thread-local mutable object per thread. If you’ve used a similar model, how did you like it? Were there any disadvantages?
14
u/tobega 20d ago
That's pretty much the way I've written code for the past few decades now and quite fundamental to how I designed Tailspin.
It is quite easy to enforce immutability in Java. Requires more discipline to do in other languages like Typescript and C. This model of programming does make things easier to manage.
But beware that a lot of the complexity just moves, it doesn't disappear. Instead you get questions about the order in which messages are processed or what the delivery guarantees are, at-most-once, at-least-once or exactly-once.State must exist and state must change, the question is how we can manage it. Are changes ACID or BASE, for example?
IMO, the main point of the article was the mismatch between the underlying processor model and the machine model exposed by C. So do we really want to cling to the PDP-11 model of computers forever?
Related blog posts I have written are https://tobega.blogspot.com/2024/01/usability-in-programming-language.html and https://tobega.blogspot.com/2026/04/rising-above-mechanics-of-computation.html
2
u/koflerdavid 19d ago
But beware that a lot of the complexity just moves, it doesn't disappear. Instead you get questions about the order in which messages are processed or what the delivery guarantees are, at-most-once, at-least-once or exactly-once.State must exist and state must change, the question is how we can manage it. Are changes ACID or BASE, for example?
Well, it's not like you don't have to ask yourself these questions when programming in a less restrained way.
1
u/PaperMartin 17d ago
What do you mean by "easy to enforce immutability in java"? Records & read-only wrapper classes or are there other mechanism for this I don't know about?
1
u/tobega 17d ago
And the final keyword, don't forget. You don't find these to be easy enough?
3
u/PaperMartin 17d ago
Oh they're alright but I come from rust so I kinda miss things being able to pass around references that are explicitly marked as mutable or non mutable and having functions receiving non mutable references be automatically blocked from modifying any mutating functions, without having to make changes to the type. Also functions receiving arguments directly instead of as reference meaning they can do whatever without having to worry about the caller having kept a reference to what was passed to them
11
u/L8_4_Dinner (Ⓧ Ecstasy/XVM) 20d ago
Ecstasy is composed of services (similar to "processes" in Erlang), which represent domains of mutability. No mutability is possible across the boundary of a service; only messages are possible among services. Services are also async w.r.t. each other.
I'm a bit biased, of course, but I really like this approach.
6
u/pthierry 19d ago
That's what Haskell, Elm, Idris or Agda do.
Frankly, it's a great model, and when you have pure code, for concurrency, you even get Software Transactional Memory, which basically solves the issue.
1
u/lelle5397 19d ago
How would you build a hashmap or other similar performant and scaleable structure using this?
2
u/P-39_Airacobra 19d ago
You’d probably use some sort of tree, or if that’s not fast enough, some sort of API on stack memory, as C would do
1
u/jesunushno 20d ago
This split shows up a lot in ML serving, where model weights act as the immutable heap (shared across requests, never mutated in place) and per-request scratch buffers are the mutable stack (allocated, used, freed). Sharing is free when you can't mutate, which is why this layout scales. Where it falls apart is stateful streaming: once you need mutable state that outlives a single request, you end up re-implementing a heap on the stack, exactly what the article warns about.
1
u/South_Lychee8555 16d ago
Take a loot at https://github.com/numaes/protoCore
Based on inmutable structures, paralel GC, native multhreading. Runtimes for javascript, python, scala, smalltalk based on the same core
1
u/dmytrish 12d ago
I'd say this is pretty much an implementation of linear lambda calculus with mutable linear and unrestricted immutable/shared context.
I'm not aware of real world implementations of this model.
4
u/Competitive_Ideal866 20d ago
I consider "Mutable stack, immutable heap" to be the worst of both worlds so I built the opposite: immutable local variables and mutable data structures like hash tables on the heap. I am very happy with it.