> Making almost every variable const at initialization is good practice. I wish it was the default, and mutable was a keyword.
It's funny how functional programming is slowly becoming the best practice for modern code (pure functions, no side-effects), yet functional programming languages are still considered fringe tech for some reason.
If you want a language where const is the default and mutable is a keyword, try F# for starters. I switched and never looked back.
I get your sentiment, but I side on it's infuriating that it's taken this long. Lol.
F# is wonderful. It is the best general purpose language, in my opinion. I looked for F# jobs for years and never landed one and gave up. I write Rust now which has opened up the embedded world, and it's nice that Rust paid attention to F# and OCaml.
It’s because FP, great as it is, is most beneficial when 80/20’d.
Trying to do it 100% pure makes everything take significantly longer to build and also makes performance difficult when you need it. It’s also hard to hire/onboard people who can grok it.
> I wish it was the default, and mutable was a keyword.
I wish the IDE would simply provide a small clue, visible but graphically unobtrusive, that it was mutated.
In fact, I end up wishing this about almost every language feature that passes my mind. For example, I don't need to choose whether I can or can't append to a list; just make it unappendable if you can prove I don't append. I don't care if it's a map, list, set, listOf, array, vector, arrayOf, Array.of(), etc unless it's going to get in my way because I have ten CPU cores and I'll optimize the loop when I need to.
Years ago I did a project where we followed a lot of strict immutability for thread safety reasons. (Immutable objects can be read safely from multiple threads.)
It made the code easier to read because it was easier to track down what could change and what couldn't. I'm now a huge fan of the concept.
I hope this experimental language becomes usable eventually, all I hear is how you have to continuously rewrite to work around the borrow checker, accept worse performance to make everything message based, or just ignore the type system and write VB6-style code where everything is indexes in arrays to obfuscate ownership and paste 'unsafe' when it moans.
A lot of code needs to assemble a result set based on if/then or switch statements. Maybe you could add those in each step of a chain of inline functions, but what if you need to skip some of that logic in certain cases? It's often much more readable to start off with a null result and put your (relatively functional) code inside if/then blocks to clearly show different logic for different cases.
Proposing making immutable by default in C or C++ doesn't make sense due to backwards compatibility reasons. New languages like Rust have easier time making better choices with immutable by default.
Could be a compiler flag. -const-by-default. Would probably mean you need to scatter mutable across the codebase to get it to compile, but I expect some people would like to have every local annotated as const or mutable.
Yeah, I also wish it was the default. But it's a little too verbose to just sprinkle on every variable in C++. Alas. Rust gets this right, but I'm stuck with C++ at work.
Ultra-pedantic const-correctness (vs tasteful const-correctness on e.g. pass-by-reference arguments or static/big objects) catches nearly no bugs in practice and significantly increases the visual noise of your code.
If you have luxury of designing a new language or using one with default mutability then do so, but don't turn C coding styles into C++-envy, or C++ coding styles into Rust-envy.
> But it's a little too verbose to just sprinkle on every variable in C++
It's worth it, though. Every variable that isn't mutated should be const. Every parameter not mutated should be const, and so should every method that doesn't mutate any fields. The mutable keyword should be banned.
Tbh I think it's ok - as much as I also want to avoid Twitter I do encourage original sourcing, especially since these nitter services can also have downtime fairly often. As long as someone jumps in and shares a link
In JavaScript, I really like const and have adopted this approach. There are some annoying situations where it doesn't work though, to do with scoping. Particularly:
- if (x) { const y = true } else { const y = false } // y doesn't exist after the block
- try { const x = foo } catch (e) { } // x doesn't exist after the try block
Constants are useful for reasoning about code, but anyone who focuses only on making everything an immutable is missing the point. The main goal should be achieving referential transparancy.
It can be perfectly fine to use mutable variables within a block, like a function when absolutely needed - for example, in JavaScript's try catch and switch statements that need to set a variable for later use. As long as these assignments are local to that block, the larger code remains side-effect free and still easy to reason about, refactor and mantain.
Rust taught me that a language does not have to be purely functional to have everything be an expression, and ever since I first used Rust years ago I've been wishing every other language worked that way. It's such a nice way to avoid or limit the scope of mutations
You are not a Clojure programmer. You use Clojure to solve problems in a professional context. I'm sorry that there's a political tribal war based on language going on at your workplace.
But especially now that coding agents are radically enabling gains in developer productivity, you don't need to feel excluded by the artificial tribal boundaries.
There are [1] and [2] for function arguments and loop variables, respectively, but nothing for the general case. Note that a type checker will complain if you re-assign with a different type. Pylint also has [3] for redefining variables from an outer scope, but Ruff doesn't implement that yet.
> In C/C++, making almost every variable const at initialization is good practice. I wish it was the default, and mutable was a keyword.
I know it's irrelevant to his point, and it's not true of C, and it doesn't have the meaning he wants, but the pedant in me is screaming and I'm surprised it hasn't been said in the comments:
How do you know it’s real? When one is in a straitjacket for a long time, the trauma might make the mind disassociate from the body, giving an illusion of freedom.
The brain is essentially dreaming it’s escaped while the body is still programming in Java.
How does Haskell deal with things like memory-mapped I/O or signal handlers where the value of a variable can be changed by factors outside of the programmer's control?
135 comments
[ 5.2 ms ] story [ 106 ms ] threadIt's funny how functional programming is slowly becoming the best practice for modern code (pure functions, no side-effects), yet functional programming languages are still considered fringe tech for some reason.
If you want a language where const is the default and mutable is a keyword, try F# for starters. I switched and never looked back.
whats the difference between const and mutable?
F# is wonderful. It is the best general purpose language, in my opinion. I looked for F# jobs for years and never landed one and gave up. I write Rust now which has opened up the embedded world, and it's nice that Rust paid attention to F# and OCaml.
Trying to do it 100% pure makes everything take significantly longer to build and also makes performance difficult when you need it. It’s also hard to hire/onboard people who can grok it.
I wish the IDE would simply provide a small clue, visible but graphically unobtrusive, that it was mutated.
In fact, I end up wishing this about almost every language feature that passes my mind. For example, I don't need to choose whether I can or can't append to a list; just make it unappendable if you can prove I don't append. I don't care if it's a map, list, set, listOf, array, vector, arrayOf, Array.of(), etc unless it's going to get in my way because I have ten CPU cores and I'll optimize the loop when I need to.
It made the code easier to read because it was easier to track down what could change and what couldn't. I'm now a huge fan of the concept.
A lot of code needs to assemble a result set based on if/then or switch statements. Maybe you could add those in each step of a chain of inline functions, but what if you need to skip some of that logic in certain cases? It's often much more readable to start off with a null result and put your (relatively functional) code inside if/then blocks to clearly show different logic for different cases.
Ultra-pedantic const-correctness (vs tasteful const-correctness on e.g. pass-by-reference arguments or static/big objects) catches nearly no bugs in practice and significantly increases the visual noise of your code.
If you have luxury of designing a new language or using one with default mutability then do so, but don't turn C coding styles into C++-envy, or C++ coding styles into Rust-envy.
It's worth it, though. Every variable that isn't mutated should be const. Every parameter not mutated should be const, and so should every method that doesn't mutate any fields. The mutable keyword should be banned.
- if (x) { const y = true } else { const y = false } // y doesn't exist after the block - try { const x = foo } catch (e) { } // x doesn't exist after the try block
It can be perfectly fine to use mutable variables within a block, like a function when absolutely needed - for example, in JavaScript's try catch and switch statements that need to set a variable for later use. As long as these assignments are local to that block, the larger code remains side-effect free and still easy to reason about, refactor and mantain.
https://rockthejvm.com/articles/what-is-referential-transpar...
Oh well continues day job as a Clojure programmer that is actively threatened by an obnoxious python take over
But especially now that coding agents are radically enabling gains in developer productivity, you don't need to feel excluded by the artificial tribal boundaries.
If you haven't, I recommend reading: https://www.kalzumeus.com/2011/10/28/dont-call-yourself-a-pr...
[1] https://docs.astral.sh/ruff/rules/redefined-argument-from-lo...
[2] https://docs.astral.sh/ruff/rules/redefined-loop-name/
[3] https://pylint.pycqa.org/en/latest/user_guide/messages/warni...
Constant is by definition immutable.
Why can't people get it through their heads in 2025? (I'm looking at you, Rust)
The principle of reducing state changes and side-effects feels a good one.
I know it's irrelevant to his point, and it's not true of C, and it doesn't have the meaning he wants, but the pedant in me is screaming and I'm surprised it hasn't been said in the comments:
In C++ mutable is a keyword.
Then, suddenly, the enlightenment
The brain is essentially dreaming it’s escaped while the body is still programming in Java.
For example in Dart you make everything `final` by default.