Live data from Hacker News

The Temporal Dead Zone, or why the TypeScript codebase is full of var statements

vincentrolfs.dev

11–20 of 64 posts

Re: The Temporal Dead Zone, or why the TypeScript codebase is full of var statements

#11
post #2

The first example is not “terrible”, that’s just how lexical scope works. I don’t really see the point of complaining about language features like this - either learn how it works or ignore at your peril.

That's not how lexical scope works anywhere but in JavaScript. Or rather, it's the interaction between "normal" lexical scope and hoisting. In a "normal" lexically scoped language, if you tried:

    function f() {
      return x; // Syntax parsing fails here.
    }
    let x = 4;
    return f();
you would get the equivalent of a ReferenceError for x when f() tried to use it (well, refer to it) at the commented line. But in JavaScript, this successfully returns 4, because `let` inherits the weird hoisting behavior of `var` and `function`. And it has to, because otherwise this would be really weird:

    function f1() { return x; }
    let x = 4;
    function f2() { return x; }
    return Math.random() 
Would that have a 50/50 chance of returning the outer x? Would the engine have to swap which x is referred to in f1 when x gets initialized?

TDZ is also terrible because the engines have to look up at runtime whether a lexical variable's binding has been initialized yet. This is one reason (perhaps the main reason?) why they're slower. You can't constant fold even a `const`, because `const v = 7` means at runtime "either 7 or nothing at all, not even null or undefined".

In my opinion, TDZ was a mistake. (Not one I could have predicted at the time, so no shade to the designers.) The right thing to do when introducing let/const would have been to make any capture of a lexical variable disable hoisting of the containing function. So the example from the article (trimmed down a little)

    return Math.random() 
would raise a ReferenceError for `useX`, because it has not yet been declared at that point in the syntactic scope. Same with the similar

    return Math.random() 
which in current JavaScript also either returns 1 or throws a ReferenceError. I'm not against hoisting functions, and removing function hoisting would have not been possible anyway. The thing is, that's not "just a function", that's a closure that is capturing something that doesn't exist yet. It's binding to something not in its lexical scope, an uninitialized slot in its static environment. That's a weird special case that has to be handled in the engine and considered in user code. It would be better to just disallow it. (And no, I don't think it would be a big deal for engines to detect that case. They already have to compute captures and bindings.)

Sadly, it's too late now.

Re: The Temporal Dead Zone, or why the TypeScript codebase is full of var statements

#13
post #11
post #2

The first example is not “terrible”, that’s just how lexical scope works. I don’t really see the point of complaining about language features like this - either learn how it works or ignore at your peril.

That's not how lexical scope works anywhere but in JavaScript. Or rather, it's the interaction between "normal" lexical scope and hoisting. In a "normal" lexically scoped language, if you tried: function f() { return x; // Syntax parsing fails here. } let x = 4; return f(); you would get the equivalent of a ReferenceError for x when f() tried to use it (well, refer to it) at the commented line. But in JavaScript, thi…

[deleted]

Re: The Temporal Dead Zone, or why the TypeScript codebase is full of var statements

#15
post #9

This is just javascript variable hoisting: https://developer.mozilla.org/en-US/docs/Glossary/Hoisting

No, the crux of the article is that using var instead of let or const can produce a performance improvement by reducing the complexity of what the interpreter must track. They cite a surprising 8% performance boost in some cases by using var.

By crux you mean the 1 paragraph at the end where it mentions performance? That's basically a footnote to an article that spends the other 99% describing javascript variable hoisting. They cite an 8% performance boost but they don't analyze it, instead just claiming it is a lot of work for the interpreter and linking to a github issue. They've run no benchmarks. They have shown no interpreter internals. They just report that one project saw an 8% performance improvement.

They did a great job of explaining javascript variable hoisting, but that's all that they have explained.

Re: The Temporal Dead Zone, or why the TypeScript codebase is full of var statements

#16
post #11
post #2

The first example is not “terrible”, that’s just how lexical scope works. I don’t really see the point of complaining about language features like this - either learn how it works or ignore at your peril.

That's not how lexical scope works anywhere but in JavaScript. Or rather, it's the interaction between "normal" lexical scope and hoisting. In a "normal" lexically scoped language, if you tried: function f() { return x; // Syntax parsing fails here. } let x = 4; return f(); you would get the equivalent of a ReferenceError for x when f() tried to use it (well, refer to it) at the commented line. But in JavaScript, thi…

That’s not the example I’m talking about. I mean where he defines `calculation` within the curly braces of the if statement, then says it “leaked out” because he can log it below the closing brace of the if statement. That’s a perfect example of the difference between lexical scope and block scope.

Re: The Temporal Dead Zone, or why the TypeScript codebase is full of var statements

#17
post #16
post #11

Earlier quoted context omitted.

That's not how lexical scope works anywhere but in JavaScript. Or rather, it's the interaction between "normal" lexical scope and hoisting. In a "normal" lexically scoped language, if you tried: function f() { return x; // Syntax parsing fails here. } let x = 4; return f(); you would get the equivalent of a ReferenceError for x when f() tried to use it (well, refer to it) at the commented line. But in JavaScript, thi…

That’s not the example I’m talking about. I mean where he defines `calculation` within the curly braces of the if statement, then says it “leaked out” because he can log it below the closing brace of the if statement. That’s a perfect example of the difference between lexical scope and block scope.

>>> The first example is not “terrible”

There are several examples in the blog, and only one is the first. It does not include the "terrible" descriptor after it. So your comment is kind of odd because it doesn't connect to the article at all.

If you mean the first example that's described as "terrible", that's the second example and it's the one with the leaking loop variable. It kind of is terrible, Python has the same problem (and many others, Python scoping rules are not good). C used to have that problem but they at least had the good sense to fix it.

Re: The Temporal Dead Zone, or why the TypeScript codebase is full of var statements

#18
post #9

Earlier quoted context omitted.

No, the crux of the article is that using var instead of let or const can produce a performance improvement by reducing the complexity of what the interpreter must track. They cite a surprising 8% performance boost in some cases by using var.

By crux you mean the 1 paragraph at the end where it mentions performance? That's basically a footnote to an article that spends the other 99% describing javascript variable hoisting. They cite an 8% performance boost but they don't analyze it, instead just claiming it is a lot of work for the interpreter and linking to a github issue. They've run no benchmarks. They have shown no interpreter internals. They just rep…

Yes it turns out the article’s conclusion is in fact contained in the conclusion paragraph

Re: The Temporal Dead Zone, or why the TypeScript codebase is full of var statements

#19
post #16

Earlier quoted context omitted.

That’s not the example I’m talking about. I mean where he defines `calculation` within the curly braces of the if statement, then says it “leaked out” because he can log it below the closing brace of the if statement. That’s a perfect example of the difference between lexical scope and block scope.

>>> The first example is not “terrible” There are several examples in the blog, and only one is the first. It does not include the "terrible" descriptor after it. So your comment is kind of odd because it doesn't connect to the article at all. If you mean the first example that's described as "terrible", that's the second example and it's the one with the leaking loop variable. It kind of is terrible, Python has the…

You’re right about my mistake, I should have said “the second code snippet”.

Re: The Temporal Dead Zone, or why the TypeScript codebase is full of var statements

#20

This is just javascript variable hoisting: https://developer.mozilla.org/en-US/docs/Glossary/Hoisting

Yes. But what are you implying by the word "just"? It sounds like you're saying we should be taking something different away from the article's description of this behavior simply because you have put a name to it.
Post reply on HN