← Back to context

Comment by tacostakohashi

3 days ago

I'm not sure this needs to be its own language.

In C/C++, this can be done by just not using malloc() or new.

You can get an awfully long way in C with only stack variables (or even no variables, functional style). You can get a little bit further with variable length arrays, and alloca() added to the mix.

With C++, you have the choice of stack, or raw new/delete, or unique_ptr, or shared_ptr / reference counting. I think this "multi-paradigm" approach works pretty well, but of course its complicated, and lots of people mess it up.

I think, with well-designed C/C++, 90+% of things can be on the stack, and dynamic allocation can be very much the exception.

I've been switching back and forth across C/C++/Java for the past few months. The more I think about it, the more ridiculous/pathological the Java approach of every object dynamically allocated, impossible to create an object not on the heap seems.

I think the main problem is kind of a human one, that people see/learn about dynamic allocation/shared_ptr etc. and it becomes a hammer and everything looks like a nail, and they forget the prospect of just using stack variables, or more generally doing the simplest thing that will work.

Maybe some kind of language where doing dumb things is an error would be good. e.g., in C++ if you do new and delete in the same scope, it's an error because it could have been a stack variable, just like unreachable code is an error on Java.

Great feedback!

You’re absolutely right — C and C++ give you the primitives to do this manually. If every developer followed the “stack first, heap only when necessary” discipline, and carefully used unique_ptr or avoided new/delete when possible, you could achieve much of the same safety and determinism.

The difference I’m aiming for is that these constraints aren’t optional — they’re baked into the language and compiler. You don’t rely on every developer making the right choice; instead, the structure of the code itself enforces ownership and lifetime rules.

So in your terms, instead of “doing dumb things is an error,” it’s structurally impossible to do dumb things in the first place. The language doesn’t just punish mistakes with foot-guns, it makes the safe path the only path.

This also opens up other possibilities that are really awkward in C/C++, like structured concurrency with deterministic memory cleanup, restartable scopes, and safe parallel allocations, without relying on GC or heavy reference counting.

I’d be curious: if C++ had a compiler that made stack-first allocation the default and forbade escapes unless explicit, would that solve most of the problems you’ve experienced, or are there still edge cases that would require a fundamentally different runtime model?

  • As far as I'm concerned, stack-first allocation _is_ the default. It's true that the default exists in my head rather than in in a compiler, though.

    Maybe think about whether what you propose could exist as a compiler warning, or static analysis tool. Or, if you want to create your own language, go for it, that's cool too.

    For my purposes... the choice of paradigms, compilers, platforms with C++ and ability to handle and work on decades of existing code outweighs the benefits of "improved" languages, but that's just me.