Live data from Hacker News

John Carmack on mutable variables

twitter.com

541–550 of 663 posts

Re: John Carmack on mutable variables

#541

Earlier quoted context omitted.

There’s no mutating happening here, for example: if cond: X = “yes” else: X = “no” X is only ever assigned once, it’s actually still purely functional. And in Rust or Lisp or other expression languages, you can do stuff like this: let X = if cond { “yes” } else { “no” }; That’s a lot nicer than a trinary operator!

Swift does let you declare an immutable variable without assigning a value to it immediately. As long as you assign a value to that variable once and only once on every code path before the variable is read: let x: Int if cond { x = 1 } else { x = 2 } // read x here

that's oldschool swift. the new hotness would be

  let x = if cond { 1 } else { 2 }

Re: John Carmack on mutable variables

#542

I completely agree with the assertion and the benefits that ensue, but my attention is always snagged by the nomenclature. I know there are alternate names available to us, but even in the context of this very conversation (and headline), the thing is being called a "variable." What is a "variable" if not something that varies?

> What is a "variable" if not something that varies?

Really it's a constant. But they are referenced like variables, so people just get a little lazy (or indifferent) talking about it.

Re: John Carmack on mutable variables

#543

Earlier quoted context omitted.

In the context of the original discussion, TypeScript (and ES6) has const and let.

well yeah except const doesn't make objects or arrays immutable

Yeah it makes their structure immutable? Something like that. Not useless but not what you would expect.

But for non-objects and non-arrays it's fine.

Re: John Carmack on mutable variables

#544

Earlier quoted context omitted.

That example is too simple for me to grasp it. How would you code a function that iterates over an array to compute its sum. No cheating with a built-in sum function. If you had to code each addition, how would that work? Curious to learn (I probably could google this or ask Claude to write me the code).

Carmack gives updating in a loop as the one exception: > You should strive to never reassign or update a variable outside of true iterative calculations in loops. If you want a completely immutable setup for this, you'd likely have to use a recursive function. This pattern is well supported and optimized in immutable languages like the ML family, but is not super practical in a standard imperative language. Something…

You don't have to use recursion, that is, you don't need language support for it. Having first class (named) functions is enough.

For example you can modify sum such that it doesn't depend on itself, but it depends on a function, which it will receive as argument (and it will be itself).

Something like:

  def sum_(f, l):
    if not l: return 0
    return l[0] + f(f, l[1:])

  def runreq(f, *args):
    return f(f, *args)

  print(runreq(sum_, [1,2,3]))

Re: John Carmack on mutable variables

#545

I try to keep deeper mutation to where it belongs, but I'll admit to shadowing variables pretty often. If I have a `result` and I need to post-process it. I'm generally much happier doing `result = result.process()` rather than having something like `preresult`. Works nicely in cases where you end up moving it into a condition, or commenting it out to test an assumption while developing. If there's an obvious name fo…

I'm going to ignore the actual names used here - you can use any name you want. I think this pattern is vulnerable to introducing bugs that allow security bugs. I'm imagining process being some kind of sanitization or validation. Then, you have this thing called result, and some of the time it might be "safe" or processed, and sometimes not. Sometimes people will process it more or less than once with real consequences.

So yeah, definitely it is much better to name the first one in a way that makes it more clear it hasn't been processed yet.

Re: John Carmack on mutable variables

#546

Love Carmack, but hard disagree on this and a lot of similar functional programming dogma. I find this type of thing very helpful: classList = ['highlighted', 'primary'] if discount: classList.append('on-sale') classList = ' '.join(classList) And not having to think about e.g. `const` vs `let` frees up needless cognitive load, which is why I think python (rightly) chose to not make it an option.

[deleted]

Re: John Carmack on mutable variables

#547

Earlier quoted context omitted.

That example is too simple for me to grasp it. How would you code a function that iterates over an array to compute its sum. No cheating with a built-in sum function. If you had to code each addition, how would that work? Curious to learn (I probably could google this or ask Claude to write me the code).

Carmack gives updating in a loop as the one exception: > You should strive to never reassign or update a variable outside of true iterative calculations in loops. If you want a completely immutable setup for this, you'd likely have to use a recursive function. This pattern is well supported and optimized in immutable languages like the ML family, but is not super practical in a standard imperative language. Something…

While your example of `sum` is a nice, pure function, it'll unfortunately blow up in python on even moderately sized inputs (we're talking thousands of elements, not millions) due to lack of tail calls in Python (currently) and the restrictions on recursion depth. The CPython interpreter as of 3.14 [0] is now capable of using tail calls in the interpreter itself, but it's not yet in Python, proper.

[0]: https://docs.python.org/3/whatsnew/3.14.html#a-new-type-of-i...

Re: John Carmack on mutable variables

#548

Earlier quoted context omitted.

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 w…

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.

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.

Re: John Carmack on mutable variables

#549
I care less and less about things like this. At some point you will write code in some lang that have fancy keywords and stuff gets mutated anyway. Also, what people tends to do if stuff is immutable is that they hide mutation by doing deep copies with changes.

Re: John Carmack on mutable variables

#550

Earlier quoted context omitted.

Carmack gives updating in a loop as the one exception: > You should strive to never reassign or update a variable outside of true iterative calculations in loops. If you want a completely immutable setup for this, you'd likely have to use a recursive function. This pattern is well supported and optimized in immutable languages like the ML family, but is not super practical in a standard imperative language. Something…

While your example of `sum` is a nice, pure function, it'll unfortunately blow up in python on even moderately sized inputs (we're talking thousands of elements, not millions) due to lack of tail calls in Python (currently) and the restrictions on recursion depth. The CPython interpreter as of 3.14 [0] is now capable of using tail calls in the interpreter itself, but it's not yet in Python, proper. [0]: https://docs.…

Yeah, to actually use tail-recursive patterns (except for known-to-be-sharply-constrained problems) in Python (or, at least, CPython), you need to use a library like `tco`, because of the implementation limits. Of course the many common recursive patterns can be cast as map, filter, or reduce operations, and all three of those are available as functions in Python's core (the first two) or stdlib (reduce).

Updating one or more variables in a loop naturally maps to reduce with the updated variable(s) being (in the case of more than one being fields of) the accumulator object.

Post reply on HN