Live data from Hacker News

John Carmack on mutable variables

twitter.com

561–570 of 663 posts

Re: John Carmack on mutable variables

#561

Earlier quoted context omitted.

I think you missed the point. I understand that if you writing a simple function with an expected interface/behaviour then that's all you need to understand. Note this isn't something unique to a functional approach. However, somebody needs to know how the entire program works - so my question was where does that application state live in a purely functional world of immumutables? Does it disappear into the call stac…

It didn't disappear; there's just less of it. Only the stateful things need to remain stateful. Everything else becomes single-use. Declaring something as a constant gives you license to only need to understand it once . You don't have to trace through the rest of the code finding out new ways it was reassigned. This frees up your mind to move on to the next thing.

> Only the stateful things need to remain stateful.

And I think it is worth noting that there is effectively no difference between “stateful” and “not stateful” in a purely functional programming environment. You are mostly talking about what a thing is and how you would like to transform it. Eg, this variable stores a set of A and I would like to compute a set of B and then C is their set difference. And so on.

Unless you have hybrid applications with mutable state (which is admittedly not uncommon, especially when using high performance libraries) you really don’t have to think about state, even at a global application level. A functional program is simply a sequence of transformations of data, often a recursive sequence of transformations. But even when working with mutable state, you can find ways to abstract away some of the mutable statefulness. Eg, a good, high performance dynamic programming solution or graph algorithm often needs to be stateful; but at some point you can “package it up” as a function and then the caller does not need to think about that part at all.

Re: John Carmack on mutable variables

#562

Earlier quoted context omitted.

In the cases we're interested in here the variable does vary, what it doesn't do is mutate. Suppose I have a function which sums up all the prices of products in a cart, the total so far will frequently mutate, that's fine. In Rust we need to mark this variable "mut" because it will be mutated as each product's price is added. After calculating this total, we also add $10 shipping charge. That's a constant, we're (fo…

> In Rust we'd use `const` for this but in C you need to use the C pre-processor language instead to make constants, which is kinda wild. I get that you're not very familiar with C? Because in C we'd use const as well. const int x = 2; x = 3; // error: assignment of read-only variable 'x'

Perhaps they’re conflating how you can’t use “const” as a compile time constant (e.g., you can’t declare the size of an array with a “const” variable). If so, C23 solves this by finally getting the constexpr keyword from c++

Re: John Carmack on mutable variables

#563

Earlier quoted context omitted.

> It means any part of your program with a reference to the original list will not have it change unexpectedly. I don't get why that would be useful. The old array of floats is incorrect. Nothing should be using it. That's the bit I don't really understand. If I have a list and I do something to it that gives me another updated list, why would I ever want anything to have the old incorrect list?

You pass in an array to a function meant to perform a transformation on each item of the array and return the result. You pass in an array of 10 values. While the function is executing, some other thread adds two more values to the array. How many values should the result of the function call have? 10 or 12? How do you guarantee that is the case?

> While the function is executing, some other thread adds two more values to the array.

This is not something that can happen.

Re: John Carmack on mutable variables

#564
post #513

Earlier quoted context omitted.

> If you want to do an operation on fooA, you don't mutate fooA. You call fooB = MyFunc(fooA) and use fooB. This is the bit I don't get. Why would I do that? I will never want a fooA and a fooB. I can't see any circumstances where having a correct fooB and an incorrect fooA kicking around would be useful.

As Carmack points out, naming the intermediate values aides in debugging. It also helps you write code as you can give a name to every mutation. But also keep in mind that correct and incorrect is not binary. You might want to pass a fooA to another class that does not want the fooB mutation. If you just have foo, you end up with situations where a copy should have happened but didn't and then you get unwanted change…

But that's just it, why would a copy ever happen? Why would you want a correct and an incorrect version of your variable hanging about?

Re: John Carmack on mutable variables

#565

Earlier quoted context omitted.

> The methods don't mutate the array, they return a new array with the change. But then I need to update a bunch of stuff to point to the new array, and I've still got the old incorrect array hanging around taking up space. This just sounds like a great way to introduce bugs.

It ends up being quite the opposite - many, many bugs come from unexpected side effects of mutation. You pass that array to a function and it turns out 10 layers deeper in the call stack, in code written by somebody else, some function decided to mutate the array. Immutability gives you solid contracts. A function takes X as input and returns Y as output. This is predictable, testable, and thread safe by default. If…

Okay, so this sounds like it's a method of programming that is entirely incompatible with anything I work on.

What sort of thing would it be useful for?

The kind of things I do tend to have maybe several hundred thousand floating point values that exist for maybe a couple of hundred thousandths of a second, get processed, get dealt with, and then are immediately overwritten with the next batch.

I can't think of any reason why I'd ever need to know what they were a few iterations back. That's gone, maybe as much as a ten-thousandth of a second ago, which may as well be last year.

Re: John Carmack on mutable variables

#566

Earlier quoted context omitted.

In the cases we're interested in here the variable does vary, what it doesn't do is mutate. Suppose I have a function which sums up all the prices of products in a cart, the total so far will frequently mutate, that's fine. In Rust we need to mark this variable "mut" because it will be mutated as each product's price is added. After calculating this total, we also add $10 shipping charge. That's a constant, we're (fo…

> In Rust we'd use `const` for this but in C you need to use the C pre-processor language instead to make constants, which is kinda wild. I get that you're not very familiar with C? Because in C we'd use const as well. const int x = 2; x = 3; // error: assignment of read-only variable 'x'

That's not a constant, that's an immutable variable which is why your diagnostic said it was read-only.

   const int x = 2;
   int *p = &x;
   *p = 3; // Now x is 3
And since I paid for the place where I'm writing this with cash earned writing C a decade or so ago, I think we can rule out "unfamiliar with C" as a symptom.

Re: John Carmack on mutable variables

#567
post #341

Earlier quoted context omitted.

If you need new values you just make new things. If you want to do an operation on fooA, you don't mutate fooA. You call fooB = MyFunc(fooA) and use fooB. The nice thing here is you can pass around pointers to fooA and never worry that anything is going to change it underneath you. You don't need to protect private variables because your internal workings cannot be mutated. Other code can copy it but not disrupt it.

> If you need new values you just make new things. > If you want to do an operation on fooA, you don't mutate fooA. You call fooB = MyFunc(fooA) and use fooB. The beautiful thing about this is you can stop naming things generically, and can start naming them specifically what they are. Comprehension goes through the roof.

Yes, but you can do that without having loads of stale copies of incorrect data lying around, presumably.

Re: John Carmack on mutable variables

#568

Earlier quoted context omitted.

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

Neither let nor even const are immutable (const prevents reassignment but not mutation if the value is of a mutable type like object or array).

Yep, I believe you'd need to call Object.seal(foo) to prevent mutability. Haven't really had the chance to use it

Re: John Carmack on mutable variables

#569

Earlier quoted context omitted.

I think renaming an old variable is a common and sensible way to free a resource in python. If there are no valid names for a resource it will be garbage collected. Which is different in languages like C++ with manual memory management. John Carmack is a C++ programmer apparently that still has a lot to learn in python.

In the vast majority of cases, developer ergonomics are much more important than freeing memory a little earlier. In other scenarios, e.g., when dealing with large data frames, the memory management argument carries more weight. Though even then there are usually better patterns, like method chaining. FYI John Carmack is a true legend in the field. Despite his not being a lifelong Python guy, I can assure you he is s…

>developer ergonomics are much more important than freeing memory a little earlier

Preach to the python choir bro, but it should be telling when a python bro considers it's too ergonomic and wasteful.

At some point being clean and efficient about the code is actually ergonomic, no one wants to write sloppy code that overallocates, doesn't free, and does useless work. To quote Steve Jobs, even if no one sees the inside part of a cabinet, the carpenter would know, and that's enough.

tl;dr: Craftmanship is as important as ergonomics.

Re: John Carmack on mutable variables

#570

Earlier quoted context omitted.

Java mentioned!

AbstractFactoryResultFactoryProcessedResultProcessedResultProcessorBeanFactory

...BeanFactoryContextConfig

First you configure a context, then you can use that to get a bean factory and start processing your whatevers.

Post reply on HN