Top
Best
New

Posted by azhenley 10/31/2025

John Carmack on mutable variables(twitter.com)
515 points | 627 commentspage 3
acdbddh 10/31/2025|
In python its common to see code like this:

  df = pd.concat(df,other_df)
  df = df.select(...)
  ...
My eyes hurts, when I see it. It makes me avoid python. I bet the reason for this mutable code is a missing simple pipes syntax. I love pipes. In R can do:

  df |> 
    rbind(other_df) |> 
    select(...)
It feels much better.
leviathan 10/31/2025||
My eyes would hurt more if I had to look all day at the vertical misalignment of that |> operator
kec 10/31/2025||
You could always switch to a better font like Fira Code which has a ligature for this.
adregan 10/31/2025||
The gp's comment wasn't made regarding the look of the operator in its ascii representation `|>` but about the vertical misalignment.

Typically you align a pipeline like so:

     df
     |> rbind(other_df)
     |> select(...)
But these topics are largely left to code formatters these days.
kec 11/1/2025||
Weird, I have always aligned as the gp showed. I’m reasonably sure tidyverse documentation does the same (which is probably where we both picked it up from).
cubefox 10/31/2025|||
Wouldn't that be simply:

  df = pd.concat(df,other_df).select(...)
mr_luc 10/31/2025|||
Elixir too (Explorer library; default backend is Pola.rs based)

- https://github.com/elixir-explorer/explorer - https://hexdocs.pm/explorer/Explorer.html

fermisea 10/31/2025|||
pandas has a .pipe operator which works exactly like this
zenlot 10/31/2025||
Nah, it doesn't. Although you can do similar in Elixir.
shmerl 10/31/2025||
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.
NathanaelRea 10/31/2025||
They could just add a "use immutable;" directive that you place at the top of your file.
Pxtl 10/31/2025||
C# does this with the null hole. I wish more languages would take a versioning approach to defaults at the file-level.
JonChesterfield 10/31/2025|||
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.
loeg 10/31/2025|||
cpp2/cfront could plausibly do this, right? Except he doesn't want to:

https://github.com/hsutter/cppfront/wiki/Design-note%3A-cons...

shmerl 10/31/2025||
Well, if they are willing to break backwards compatibility, a lot of things can be improved, including this.
_flux 10/31/2025||
Maybe the new C++ profiles that are supposedly going to make C++ a safe language could do it.
shermantanktop 10/31/2025||
Const/final by default - preach it, brother, amen and hallelujah. Mutability by default is the rule in the big languages and the world would be a better place if it weren’t.
storus 10/31/2025||
I had enormous fun optimizng C++ via self-modifying assembly to squeeze the utmost performance of some critical algorithms, and now this drive towards immutable everything feels like cutting my hands and legs off and forcing me to do subpar engineering.
no_wizard 10/31/2025||
Compiler optimizations make up for it, usually. Thats been my experience at least.

An important thing to keep in mind is just how far compilers have come over the least 40 years. Often, with immutable languages, they can do extremely efficient compile only optimizations because of said guaranteed immutability by default.

Its not true in every case, of course, but I think for most situations compilers do a more than good enough job with this.

ryandrake 10/31/2025||
Same here, I grew up in a world where you had a handful of registers and a bunch of memory locations, and those were your variables.

                clc
                lda value
                adc #1
                sta value
                lda value+1
                adc #0
                sta value+1

    value       .byte 0,0
These constraints are pretty much built into my concept of programming and it would take great effort to break out of it. It feels nice doing:

    x = 20
    x = x + func(y)
    x = x / func(z)
And it would feel weirdly wasteful to do:

    x = 20
    x1 = x + func(y)
    x2 = x1 / func(z)
Like, I know that variables are no longer a scarce resource, but my brain still wants to conserve them.
1718627440 10/31/2025||
To me this also seem to be wasteful, even if not for the computer, but it wastes my amount of working state I can keep in my head, which is very limited.
restalis 10/31/2025||
I was thinking about this too. When you read a program, there is this information payload, which is the metaphorical ball you have to keep your eyes on, and more or less forget about the rest as soon as it isn't relevant any more. In the functional paradigm it's like seeing the juggle of a bunch of such balls instead (plus the expectation to admire it), but that's just wasteful on reader's attention.
loeg 10/31/2025||
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.
veltas 10/31/2025||
100%, life's too short.

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.

maleldil 10/31/2025||
> 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.

loeg 10/31/2025||
Const annotations are worth it for methods and APIs, but not most local variables.
maleldil 11/1/2025||
I'd argue that it is. Use const by default, so it's obvious to the reader if something is mutated or not. It's easier to read code when you don't have to worry about how values may change over time. This is why Rust made the right choice.
loeg 11/1/2025||
Yeah, I think it's a great default, and Rust got that right. It's just too noisy in C++ as the non-default.
DonHopkins 10/31/2025||
Did you ever have one of those days when variables won't and constants aren't?
waffletower 10/31/2025||
Would be beneficial if Rich Hickey's opinion and experience regarding mutable state was given more weight than John Carmack's.
Razengan 10/31/2025||
If designing your hypothetical ideal language, what are some intuitive/cute keywords you would choose for mutables/immutables?

`let` is so 2020. `const` is too long. `static` makes me fall asleep at the keyboard. `con` sounds bad. How about

`law`?

    law pi = 3.142 (heh typing on Mac autocompleted this)

    law c = 29979245

    law law = "Dredd"
or `set` or `once` or `make`?
tomaytotomato 10/31/2025||
There was a proposal in Java a few years back to introduce "val".

I think it never gained traction but it would have been nice to have this in Java

    val firstName = "Bob";
    val lastName = "Tables";
    var fullName = "";

    fullName = firstName + " " + lastName;
Razengan 10/31/2025|||
That's an aesthetically awkward and also bug-prone syntax: So just a difference of 1 single letter (that looks similar) to mean the completely opposite thing?? Nah you don't want that, and I don't either.
nvlled 10/31/2025|||
Kotlin uses var/val too[0] which is what Java is trying to copy. I have never written any kotlin code before, so I don't know if this would be a problem in practice. On the plus side, var and val both have the same length, so the variable declaractions are properly aligned. The names are also intuitive as far as I can tell.In theory, I'd probably be okay with it.

[0] https://kotlinlang.org/docs/basic-syntax.html#variables

ahoka 10/31/2025||
Not a problem in practice as you use val 99.99% percent of the cases (which shows why immutability should be the default, because most often that is needed) and Idea underlines any mutable references, so the sticks out. It also suggests val when a var is not actually mutated.
dionian 10/31/2025|||
They're intuitively named. A value is a value. A variable is a variable.
Razengan 10/31/2025||
A variable is also a value.
mcdeltat 10/31/2025|||
Wouldn't this "val" be the same as "final"?

Also related, it annoys me that Java has final but otherwise poor/leaky support for immutability. You can mark something final but most Java code (and a lot of the standard library) uses mutable objects so the final does basically nothing... C++ "const" desparately needs to spread to other languages.

veltas 10/31/2025|||
What is wrong with let?
Razengan 10/31/2025||
Nothing, it's just been done, just trying to think of some better/newer ways to say it :)
teo_zero 11/1/2025||
Why not "def"?
Razengan 11/1/2025||
That's fine. But couldn't that just mean "define" any value at all?

There's nothing in it to say it's specifically for defining a value only ONCE.

Const-me 10/31/2025||
For performance critical code, you want to reuse L1D cache lines as much as possible. In many cases, allocation of a new immutable object boils down to malloc(). Newly allocated memory is unlikely to be found on L1D cache. OTOH, replacing data in recently accessed memory and reusing the memory is very likely to become L1D cache hit in runtime.
marginalia_nu 10/31/2025||
For performance critical code, you wouldn't use malloc()-allocation at all, though whether using an arena allocator or putting stuff on the stack, your argument is still sane. Data locality is speed.
ramses0 10/31/2025||
"Immutability" from a programming language statement perspective doesn't necessarily imply that the implementation duplicates memory or variables.

Similar to how "tail recursion can (usually) be lifted/lowered to a simple loop...", immutability from language statements can often be "collapsed" into mutating a single variable, and there may be one or two "dances" you need to do to either add helper functions, structure your code _slightly_ differently to get there, but it's similar to any kind of performance sensitive code.

Example foo(bar(baz(), bar_alt(baz_alt(), etc...))) [where function call nesting is "representing" an immutability graph] ...yeah, that'd have a lot of allocations and whatever.

But: foo().bar().bar_alt().baz().baz_alt().etc(...) you could imagine is always just stacking/mutating the same variable[s] "in place".

...don't get hung up on the syntax (it's wildly wrong), but imagine the concept. If all the functions "in the chain" are pure (no globals, no modifications), then they can be analyzed and reduced. Refer back to the "Why SSA?" article from a week or two ago: https://news.ycombinator.com/item?id=45674568 ...and you'll see how the logical lines of statements don't necessarily correspond to the physical movement of memory and registers.

Const-me 10/31/2025||
You’re describing an edge case. Generally speaking, memory is only reused after old objects are deallocated. And here’s the relevant quote from the OP’s post:

> Having all the intermediate calculations still available is helpful in the debugger

nyrp 10/31/2025|
Is he referring to something specific with "true" iterative calculations vs. plain old iterative ones, assuming they are in some way "non-true" or less "true"? Like, avoiding i+=x in favor of ++i or something? Or maybe am I just tired today.
ufo 10/31/2025|
I think he's just saying that mutation is ok if it's something loopy, like changing the loop counter or updating some running sum. So both i+=1 and ++i are fine.
More comments...