How necessary are var, let, and const?
raganwald.com
raganwald.com
It's really hard to get a declaration-free language right. Python was the biggest success to date.
1) It means that every place the const appears it can be replaced with the const's value. Type checking can be streamlined, less indirection.
2) It communicates the developer's INTENT in an enforced manner. No later code change can accidentally make the const suddenly non-const.
3) const + deep Object.freeze() makes for a complete const.
Sure a human could hypothetically scan the code to see that the value has not been reassigned. This falls apart in practice. As soon as the company has a few dozen developers the code is constantly changing and such manual analysis would have to be constantly done.
2.) That's nice but JS semantics do not actually hold up. The intent is for a constant, the reality is there is a small window where the wrong results can be observed. Engines don't actually do any more optimizations than for var or let; in fact, your code may actually be slower due to the live-range hole checks.
function f() { console.log(a); const a = 1; console.log(a); }
...actually returns this:
undefined 1
So you get partially compile-time semantics (you can't assign to a) but partially run-time semantics (a only gets its value when initialised). Simply propagating the value of a's initialiser to all places where the variable is used is wrong, as this behaviour's required by the spec.
> ReferenceError: can't access lexical declaration `a' before initialization
> The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s LexicalBinding is evaluated.
I.e. given a variable declared with `const`, you may not access it before it is set.
[1] http://people.mozilla.org/~jorendorff/es6-draft.html#sec-let...
The trouble with this approach is that runtime checks are only a guarantee that the code you've _exercised_ does not break the contract.
In that respect, `const` is deeply different than `.freeze`, in the same way that runtime assertions are deeply different than type checking.
Javascript is dynamically weakly typed but it is still typed, typeof/instanceof exist for a reason.
my point is if you are using a weakly typed language, it doesn't care much about developer intent with respect to type. so why would it be concerned with developer intent with respect to mutability? seems arbitrary.
I am simply repeating the well-known benefits to immutables which is completely orthogonal to a type system, static or otherwise.
const a = {};
Object.setPrototypeOf(a, SomethingElse);Remember I have said const PLUS Object.freeze() Both are needed to get the true immutable effect.
That said, can somebody implement hygienic macros in JavaScript. They will probably help will people having to explain basics knowledge over and over.
Personally I find excessive use of lamdas create unmaintainable and incredibly difficult to debug spaghetti code. The idea that JS developers should make their code even more LISP-like is enough to give me nightmares.
Why? Are you also annoyed by calculus students who learn ideas today that have been known for hundreds of years?
> That said, congratulation for learning value of syntactical sugar. I hope you like it.
Maybe I am misreading this (it could mean simply what it literally says), but I read it as unconstructive snark.
Is there a benefit in spreading this discovery to others, even after it's been known so long? Certainly I think so; it's new to everyone at some point, and, since I wasn't originally motivated to read McCarthy's original papers, I wouldn't have discovered the ideas of Lisp without recent expositions of it. Granting the benefit of this, who can better communicate with the unenlightened, in terms familiar to them, than a recent convert? (Although, as braythwayt points out (https://news.ycombinator.com/item?id=9641279), he is scarcely a newcomer to the party.)
The designers of let are largely a bunch of Schemers; they knew what they were doing.
Although I haven't used it hands-on, http://sweetjs.org/ looks impressive.
For example recently sweet.js apparently implemented some cutting-edge Racket macro developments before Racket officially did. :) https://github.com/mozilla/sweet.js/pull/461
"Whereas, const […]. It is not nearly as useful as immutable data, because the problem it solves is easy, not hard."
To something like:
"const may be more useful than adding something like immutable data to an imperative language with mutability deep in its DNA might be because it helps with one of the hardest problems; long-term, correct re-reading by humans doing maintenance or extension."
But, the OP covers that well earlier in, so I'm not sure a third take on it would add much. Thanks for doing the exploration!
Why you would ever do that, however...
function f() {
const queue = [];
consumer(queue);
return queue;
}
It could be important to note that removing const has benign effect, but that it is there to ensure a programmer does not change the value of queue between `consumer(queue)` and `return queue`. Easily reasoned about, but extra safeguards from introducing bugs is always nice. function silly(x, y, z, args) {
args = Array.prototype.slice.call(arguments);
args.shift();
args.shift();
args.shift();
args.shift();
x = y = z = undefined;
// regular function goes here
}(Having said which, I notice that there's a reply from the person who actually wrote the article, and it doesn't say that. But that's why he should have made the reference :-).)
Scheme vs. Common Lisp, and all that.
function constUseful () {
var guarded = 1;
(function loop (orgGuarded) {
setTimeout(function () {
if (guarded !== orgGuarded) {
throw 'guarded reassigned!';
}
loop(orgGuarded);
}, 0);
})(guarded);
guarded = 2;
}
constUseful();
That's an approximation of const's value as delineated in code.An even better question is why not get rid of var and make every variable local to its parent function? To alter globals, use the window object explicitly.
I agree, but I think the solution is to stop using `var`, the question is how useful `var` really is. `let`'s scoping is what it appears to be, `var`'s is not. So `let` is the better choice.
But in practice, there are many cases when I have to create multiple callbacks in a loop; half the time I forget that, in Javascript, declaring a variable inside a loop does not actually create a variable local to the loop, and so have to keep debugging why all my callbacks are behaving exactly the same.
The let statement appears to adopt Lua-style lexical scoping, which will be a breath of fresh air once I can rely on browser support.
JS is used in non-DOM contexts as well. Though, of course, if that big a change is being made, a generic substitute for `window` could also be specified.
Isn't that just |this| at the top level?
In node, there is a name for the default global: "global", which is also the default context. So node gives it a "generic substitute" as the OP suggested. Most people use "this" to make assignments to it, rather than the "global" name, since it is usually accessed from the default context.
const is a different case, but IMO there's no need to use var when let exists.
I think his point was simply that examining how to emulate let/var with closures, it shows you explicitly what is different/similar about them. He's not suggesting anyone use those transforms.
There is a proposal for that, coincidentally called "strong mode".
https://docs.google.com/document/d/1Qk0qC4s_XNCLemj42FqfsRLp...
My opinion is that if you use let, don't use var, and if you use var, don't use let. Either one on its own is fine, together they are just a mess.
I do not think that is true, a called function can side effect the caller environment via `arguments` if that is passed around.
> The obsolete `arguments.caller` property used to provide the
> function that invoked the currently executing function. This
> property has been removed and no longer works.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...Can you provide an example of modifying a declared variable in a calling environment? I'm very interested!
function sidEffecting(ary) {
ary[0] = ary[2];
}
function bar(a,b,c) {
c = 10
sidEffecting(arguments);
return a + b + c;
}
bar(1,1,1) // I expect 12, but is 21
I now realize this could actually be not allowed anymore in recent ES, I am not sure, but copy & paste in chrome console still prints 21.