Posted by azhenley 10/31/2025
Anyway the outcome of trying to avoid mutation means instead of simply setting player.score you get something like player = new Player(oldPlayerState, updates). This is of course slow as hell. You're recreating the entire player object to update a single variable. While it does technically only mutate a single object rather than everything individually it's not really beneficial in such a case.
Unless you have an object with a lot of internal rules across each variable (the can't be 'A' if 'B' example above) it's probably wrong to push the mutation up the stack like that. The simple fact is a complex computer program will need to mutate something at some point (it's literally not a turing machine if it can't) so when avoiding mutation you're really just pushing the mutation into a higher level data object. "Avoid mutations of data that has dependencies" is probably the correct rule to apply. Dependencies need to be bundled and this is why it makes sense not to allow 'A' in the above example to be mutated individually but instead force the programmer to update A and B together.
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.1.
classList = ['highlighted', 'primary']
.concatif(discount, 'on-sale')
.join(' ')
2. classList = ' '.join(['highlighted', 'primary'] + (['on-sale'] if discount else []))
3. mut classList = ['highlighted', 'primary']
if discount:
classList.append('on-sale')
classList = ' '.join(classList)
freeze classList
4. def get_class_list(discount):
mut classList = ['highlighted', 'primary']
if discount:
classList.append('on-sale')
classList = ' '.join(classList)
return classList
classList = get_class_list(discount) (table.concat [:highlighted :primary (if discount :on-sale)] " ")Wouldn't this be an easy task for SCA tool e.g. Pylint? It has atleast warning against variable redefinition: https://pylint.pycqa.org/en/latest/user_guide/messages/refac...
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.
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! let x: Int
if cond {
x = 1
} else {
x = 2
}
// read x here let x = if cond { 1 } else { 2 }The value (pun intended) of the latter is that once you’ve arrived at a concrete result, you do not have to think about it again.
You’re not defining a “variable”, you’re naming an intermediate result.
- 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
const myArray = [1,2,3]
myArray.push(4)
myArray // [1, 2, 3, 4] const y = (() => {
if (x) {
return true;
} else {
return false;
})(); const y = (x === true) ? true : false;
I used this kind of style for argument initialization when I was writing JS code, right at the top of my function bodies, due to ES not being able to specify real nullable default values. (and I'm setting apart why I think undefined as a value is pointless legacy). Composite.prototype.SetPosition(x, y, z) {
x = (isNumber(x) && x >= 0 && x <= 1337) ? x : null;
y = (isNumber(y) && y >= 0 && y <= 1337) ? y : null;
z = isNumber(z) ? z : null;
if x !== null && y !== null && z !== null {
// use clamped values
}
} function SetPosition(x, y, z) {
if (!(isNumber(x) && isNumber(y) && isNumber(z))) {
// Default vals
return;
}
x = clamp(x, 0, 1337);
y = clamp(y, 0, 1337);
z = z;
}In JS, errors are pretty painful due to try/catch, that's why I would probably these days recommend to use Effect [1] or similar libraries to have a failsafe workflow with error cases.
Errors in general are pretty painful in all languages in my opinion. The only language where I thought "oh this might be nice" was Koka, where it's designed around Effect Types and Handlers [2]
const y = x ? true : false;
const y = (bool)x;
or const bool y = x;val result = if (condition) { val x = foo() y = bar(x) y + k // return of last expression is return value of block } else { baz() }
Or:
val q = try { a / b } catch (e: ArithmeticException) { println("Division by zero!") 0 // Returns 0 if an exception occurs }
Edit: ugh, can't get the formatting to work /facepalm.