News for hackers. Stuff that matters.
Re:Is there any code in Firefox (as of 2020) that comes from... by anonymoushn on Saturday March 28, 2020 @12:55AM (#22709303)
is this because you think having one dynamically scoped variable is clearer than having 0?
Re:Is there any code in Firefox (as of 2020) that comes from... by austincheney on Saturday March 28, 2020 @01:16AM (#22709389)
I think arrow functions are less clear because they are always anonymous functions. Anonymous functions complicate stack traces and performance profiles.
Re:Is there any code in Firefox (as of 2020) that comes from... by minitech on Saturday March 28, 2020 @03:18AM (#22709743)
They can’t be named in the same standalone way that non-arrow function expressions can, but they do acquire names in some positions that get used in stack traces and profiles.

  > ({ literalProperty: () => {} }).literalProperty.name
  'literalProperty'

  > ({ ['computedName']: () => {} }).computedName.name
  'computedName'

  > const variable = () => {};
  > variable.name
  'variable'
So if you want to name an arrow function, you can usually assign it to a variable.
Re:Is there any code in Firefox (as of 2020) that comes from... by austincheney on Saturday March 28, 2020 @05:12AM (#22710073)
Re:Is there any code in Firefox (as of 2020) that comes from... by roblabla on Saturday March 28, 2020 @07:33AM (#22710490)
Your parent specifically talked about giving it a name in thte stack frame. And assigning an anonymous function to a constant/object and using it through that assignment will cause the stack trace to show a name.
Re:Is there any code in Firefox (as of 2020) that comes from... by austincheney on Saturday March 28, 2020 @08:42AM (#22710787)
The only way to arbitrarily generate a JavaScript stack trace without an error, in both modern browsers and Node, is the following code sample. In order to prove the output of a stack trace you need logic that actually produces a stack trace.

   new Error().stack
The following demonstrations take the prior examples and put the stack call into the arrow function bodies and wrap that in an arbitrary function for an additional line in the stack trace output.

The first example assigns the arrow function to an object property. And then generates the name of the object's property name. This does nothing to describe the function. Here is a better example:

    var stack,a=function(){({ myProperty: () => {stack = new Error().stack;} }).myProperty();};a();stack;
In the browser that outputs:

    "myProperty@debugger eval code:1:59
    a@debugger eval code:1:82
    @debugger eval code:1:102
Its a bit more clear in Node's REPL

    'Error\n' +
      '    at Object.myProperty (repl:1:59)\n' +
      '    at a (repl:1:82)\n' +
      '    at repl:1:102\n' +
      '    at Script.runInThisContext (vm.js:120:20)\n' +
      '    at REPLServer.defaultEval (repl.js:432:29)\n' +
      '    at bound (domain.js:429:14)\n' +
      '    at REPLServer.runBound [as eval] (domain.js:442:12)\n' +
      '    at REPLServer.onLine (repl.js:759:10)\n' +
      '    at REPLServer.emit (events.js:333:22)\n' +
      '    at REPLServer.EventEmitter.emit (domain.js:485:12)'
Essentially the stack traces represent a method call as designated by a function whose identity is bound to an object property, but the function itself remains unnamed. The second example is logically identical to the first except for the minor syntax difference of array notation versus a word type variable name.

The third example is logically different than the prior two examples:

    var stack,a=function(){var myVariable = () => {stack = new Error().stack;};myVariable();};a();stack;
Browser: "myVariable@debugger eval code:1:51 a@debugger eval code:1:71 @debugger eval code:1:81

Node: 'Error\n' + ' at myVariable (repl:1:51)\n' + ' at a (repl:1:71)\n' + ' at repl:1:81\n' + ' at Script.runInThisContext (vm.js:120:20)\n' + ' at REPLServer.defaultEval (repl.js:432:29)\n' + ' at bound (domain.js:429:14)\n' + ' at REPLServer.runBound [as eval] (domain.js:442:12)\n' + ' at REPLServer.onLine (repl.js:759:10)\n' + ' at REPLServer.emit (events.js:333:22)\n' + ' at REPLServer.EventEmitter.emit (domain.js:485:12)'

The output of assigning an arrow function is identical, in both environments, to assigning a regular anonymous function:

    var stack,a=function(){var myVariable = function () {stack = new Error().stack;};myVariable();};a();stack;
That is different than assigning to a named function:

    var stack,a=function(){var myVariable = function myFunctionName() {stack = new Error().stack;};myVariable();};a();stack;

    'Error\n' +
      '    at myFunctionName (repl:1:76)\n' +
      '    at a (repl:1:96)\n' +
      '    at repl:1:111\n' +
      '    at Script.runInThisContext (vm.js:120:20)\n' +
      '    at REPLServer.defaultEval (repl.js:432:29)\n' +
      '    at bound (domain.js:429:14)\n' +
      '    at REPLServer.runBound [as eval] (domain.js:442:12)\n' +
      '    at REPLServer.onLine (repl.js:759:10)\n' +
      '    at REPLServer.emit (events.js:333:22)\n' +
      '    at REPLServer.EventEmitter.emit (domain.js:485:12)'
And both of those are different to anonymous functions not assigned to a variable. Both of the following examples produce the same output:

    var stack,a=function(){(function () {stack = new Error().stack;}());};a();stack;

    var stack,a=function(){() => {stack = new Error().stack;};};a();stack;

    'Error\n' +
      '    at repl:1:46\n' +
      '    at a (repl:1:65)\n' +
      '    at repl:1:71\n' +
      '    at Script.runInThisContext (vm.js:120:20)\n' +
      '    at REPLServer.defaultEval (repl.js:432:29)\n' +
      '    at bound (domain.js:429:14)\n' +
      '    at REPLServer.runBound [as eval] (domain.js:442:12)\n' +
      '    at REPLServer.onLine (repl.js:759:10)\n' +
      '    at REPLServer.emit (events.js:333:22)\n' +
      '    at REPLServer.EventEmitter.emit (domain.js:485:12)'
You can see in the first anonymous function example that an IIFE (immediately invoked function expression) is used. Function's require identity, aside from 3 exceptions, otherwise they throw an error. The three exceptions are arrow functions, IIFE, and function arguments.

So much of this discussion is nonsense though, because it doesn't make sense to arbitrarily complicate your code with unnecessary objects merely to provide your anonymous arrow functions with identity. The whole point of arrow functions is to reduce syntax and thereby provide easier to read code, which only the third of those three examples provide.

It is also helpful to understand that a function's name is an identity known to the function, which means it is available to the internal logic of the function as a local reference and not a scoped reference. The identity of a variable name to which a function is assigned will always be a scoped reference, and that distinction also results in different output in stack traces.

Furthermore, none of those examples demonstrates the most important use case, callbacks, or functions as arguments to event handlers. In Node the callbacks become nested very quickly and often times many layers deep. Each use of an arrow function is an anonymous line in the call stack and several layers of anonymous calls is less helpful to read. It's not hopeless because the stack trace provides the location of each call, but you have to dive into the code on each line mentioned to see what is actually happening instead of just reading the function names from a more helpful stack trace.

Re:Is there any code in Firefox (as of 2020) that comes from... by minitech on Saturday March 28, 2020 @01:15PM (#22712539)
This seems like a very verbose retread.

What I was saying is if you are currently using a named function:

  function foo(bar) {
      // …
  }
you don’t lose the name by making it an arrow function:

  const foo = bar => {
      // …
  };
and yes, you can name your callbacks and event handlers like this before passing them to functions. Introducing variables to name values (any values, not just functions) doesn’t really complicate code. Many times, it can be a readability improvement.
Re:Is there any code in Firefox (as of 2020) that comes from... by DonHopkins on Saturday March 28, 2020 @01:32AM (#22709451)
Guido wrote a fascinating article about why Python lambdas are expressions and not functions, so if you want multiple statements, you have to def a function and refer to it by name.

https://www.artima.com/weblogs/viewpost.jsp?thread=147358

>All Things Pythonic: Language Design Is Not Just Solving Puzzles. By Guido van van Rossum, February 10, 2006.

>Summary:

>An incident on python-dev today made me appreciate (again) that there's more to language design than puzzle-solving. A ramble on the nature of Pythonicity, culminating in a comparison of language design to user interface design.

[...]

http://lambda-the-ultimate.org/node/1298

>Guido: Language Design Is Not Just Solving Puzzles

>And there's the rub: there's no way to make a Rube Goldberg language feature appear simple. Features of a programming language, whether syntactic or semantic, are all part of the language's user interface. And a user interface can handle only so much complexity or it becomes unusable.

>The discussion is about multi-statement lambdas, but I don't want to discuss this specific issue. What's more interesting is the discussion of language as a user interface (an interface to what, you might ask), the underlying assumption that languages have character (e.g., Pythonicity), and the integrated view of semantics and syntax of language constructs when thinking about language usability.

[...]

Re:Is there any code in Firefox (as of 2020) that comes from... by m1sta_ on Saturday March 28, 2020 @02:03AM (#22709533)
There is cognitive load associated with remembering a simple function that is only used once, versus seeing it is usage. Arrow functions can be effectively self documenting.
Re:Is there any code in Firefox (as of 2020) that comes from... by DonHopkins on Saturday March 28, 2020 @02:05AM (#22709540)
What's hard to document is why there is any need for non-arrow functions.

In the original language design I mean, since non-arrow functions with dynamic "this" only make sense in the context of having been mistakenly baked into the language from day one (or so). If JavaScript started out with only fat arrow functions, and had a simpler way of passing the current object like Python's or CLOS's or Dylan's or ScriptX's explicit "self" parameter, there would have been no confusion or automatic nuclear foot guns or need for two subtly semantically and syntactically different kinds of functions.

Any JavaScript programmer who doesn't clearly understand the difference between non-arrow and arrow functions, and the nuances of dynamically bound "this", and when to use each type of function, is dangerous and libel to write subtly buggy code. Because there should only be one type of function!

There was no reason to design the language and function syntax and semantics in such a mistakenly complex fragile way, that eventually spawned millions of blog posts explaining the nuances and dangers of "this". Because you know that behind every one of those helpful blog posts is a well intentioned programmer who got screwed by "this", and wanted to help other people avoid their mistakes.

I've been programming JavaScript for years, and I STILL get screwed by "this". Whenever something goes inexplicable wrong and I find myself pounding my head up against a cinderblock in frustration because I can't figure it out, I take a step back and search my recent changes for "this", and in most cases, I've just accidentally used a function instead of a fat arrow.

There were plenty of other languages that could have served as examples of the right way to do it, like Smalltalk or Python or Common Lisp CLOS or Dylan, but they were ignored when JavaScript was designed.

Re:Is there any code in Firefox (as of 2020) that comes from... by saagarjha on Saturday March 28, 2020 @03:08AM (#22709715)
> Anonymous functions complicate stack traces and performance profiles.

It depends. Often you can optimize them out.

Re:Is there any code in Firefox (as of 2020) that comes from... by rejschaap on Saturday March 28, 2020 @05:25AM (#22710117)
Doesn't that just complicate things even more?
Re:Is there any code in Firefox (as of 2020) that comes from... by DonHopkins on Saturday March 28, 2020 @01:18AM (#22709398)
It always struck me about JavaScript, that if you were going to choose one variable and one variable only to be dynamically scoped (for whatever strange reason), "this" would be the absolute worst one to choose that you possibly could, an automatic nuclear foot-gun that would trip you up every time. If you ever wanted a function to lexically close over a variable, but could choose only one, "this" would be it!

Fat arrow functions struck me like one of those half-assed solutions Trump (edit: or Obama) comes up with for a terrible problem of his own creation, a foolish mistake that nobody in their right mind would have ever made in the first place. And then he expects praise for his solution, and nobody remembers he caused the problem it was supposed to solve in the first place.

I agree with the sibling comment by austincheney: JavaScript would have been a much simpler and less bug-prone language if not for "this" being dynamically scoped and magical, which later required nailing fat arrow functions onto the side, that were almost but not quite entirely unlike functions.

Have you ever tried explaining why there are two different kinds of functions in JavaScript to a beginning programmer, and seen their eyes glaze over when you digressed into the nuances of "this", lexical scoping, dynamic scoping, call and apply, closures, and binding functions? You have to understand all that before you truly understand functions in JavaScript, and much of it is irrelevant crap.

Lexical, dynamic, both, or neither? Pick a lane, JavaScript!

Re:Is there any code in Firefox (as of 2020) that comes from... by pwdisswordfish2 on Saturday March 28, 2020 @09:50AM (#22711117)
‘this’ is not in any sense dynamically scoped. It's just a function parameter, assigned implicitly based on the context of the call.
Re:Is there any code in Firefox (as of 2020) that comes from... by DonHopkins on Sunday March 29, 2020 @09:03PM (#22724289)
If that's a fact, then please tweet to Brendan Eich that he was wrong when he referred to "dynamic this binding" as the rationale for adding fat arrow functions to JavaScript in his fat arrow proposal, and take your argument up with him, not me:

>"dynamic this binding is an oft-fired footgun" -Brendan Eich

https://tc39wiki.calculist.org/es6/arrow-functions/

Re:Is there any code in Firefox (as of 2020) that comes from... by BrendanEich on Tuesday March 31, 2020 @03:07AM (#22735484)
I wrote dynamic binding, that's not the same as dynamic scope.
Re:Is there any code in Firefox (as of 2020) that comes from... by minitech on Saturday March 28, 2020 @01:59AM (#22709522)
Do you mean you wouldn’t have named it “this”? Because if `this` weren’t set by the means of calling in ES5 and earlier, it would have no point at all.
Re:Is there any code in Firefox (as of 2020) that comes from... by DonHopkins on Saturday March 28, 2020 @02:27AM (#22709602)
It doesn't matter what it's named. It matters how it's passed. Python, Common Lisp CLOS, ScriptX, even NeWS's object oriented PostScript, all pass "self" as a first explicit parameter.

C++ does it behind the scenes, but it's just a hidden parameter, not a property of the hidden "virtual machine", because C++ doesn't have a virtual machine. But if you look at the C code generated by the CFront C++=>C compiler, you will see that every method has an explicit first "this" parameter whose type is the class it's defined in.

The way "this" is defined in JavaScript unnecessarily exposes the internal implementation details of the first JavaScript interpreter, which all subsequent JavaScript interpreters and compilers then had to be compatible with.

Simply knowing about normal function parameters and lexical binding like in Python is not enough: There is an invisible a VM interpreter thread somewhere that you have to know about, which has a "this" property (or "horrible global object", as Douglas Crockford puts it), and the only way to change it is indirectly through method applications with ".", or by using call and apply. So JavaScript "this" is a magic keyword, not just a normal parameter like all the rest. In the same way JavaScript "arguments" is magic, not just a normal argument like Python or Lisp &rest arguments.

And this needlessly adds to the complexity and surface area of the language, and bakes in unwanted behaviors like dynamic binding, when most of the civilized world agrees that lexical binding is superior, less surprising, and easier to reason about, and dynamic binding should be the exception that you have to go out of your way to use, not the default behavior for the implicit first argument of every method or function.

Re:Is there any code in Firefox (as of 2020) that comes from... by minitech on Saturday March 28, 2020 @02:35AM (#22709629)
> Simply knowing about normal function parameters and lexical binding like in Python is not enough: There is an invisible a VM interpreter thread somewhere that you have to know about, which has a "this" property, and the only way to change it is indirectly through method applications with ".", or by using call and apply. So "this" is not just a normal parameter like all the rest.

That sounds like an unnecessarily complicated and possibly wrong way to think about it. `this` acts exactly like a parameter in ES5 strict mode (`x.f()` being `f.call(x)` and `f()` being `f.call(undefined)`), and does not act like dynamic binding.

Re:Is there any code in Firefox (as of 2020) that comes from... by DonHopkins on Saturday March 28, 2020 @02:44AM (#22709654)
And ES5 strict mode was retroactively designed in 2008, in a way that had to maintain backwards compatibility with the mistakes of 1997, 11 years earlier. By then the mistake was already irreversibly baked deeply into the language.

JavaScript will always suffer from that mistake, no matter how much they try to paper over it with strict mode or TypeScript. It's way too late to remove non-fat-arrow functions from JavaScript, so they will always be a foot gun, whether or not you're using strict mode.

If you define a non-fat-arrow function and mention "this", and then pass it out to somebody you don't know or have any control over or contact with, who calls that function without going out of their way to properly bind it with call or apply, then they will be screwed.

Re:Is there any code in Firefox (as of 2020) that comes from... by minitech on Saturday March 28, 2020 @02:52AM (#22709677)
I don’t think it’s a mistake. I think it’s a sensible design choice (after strict mode disconnected it from the actual misfeature that is primitive wrappers).

There are arguments to be made that it’s confusing coming from other languages given that it acts nothing like their “this”es, but I’m not sure that “properties of invisible VM interpreter threads” are related at all.

Re:Is there any code in Firefox (as of 2020) that comes from... by DonHopkins on Saturday March 28, 2020 @02:57AM (#22709684)
If "this" wasn't a mistake and a loaded footgun, then why did Brendan Eich himself literally say that "dynamic this binding is an oft-fired footgun" in the "Rationale" section of his original fat "Arrow Functions" proposal?

And why did Douglas Crockford say "this" was "horrible", and that ES5/strict mode was "much less wrong than binding the global object, but is still not right"?

And why is "this" always showing up as #1 in the lists of "10 Most Common JavaScript Mistakes"?

https://www.toptal.com/javascript/10-most-common-javascript-...

>Buggy JavaScript Code: The 10 Most Common Mistakes JavaScript Developers Make

>Common Mistake #1: Incorrect references to this

>I once heard a comedian say:

>I’m not really here, because what’s here, besides there, without the ‘t’?

>That joke in many ways characterizes the type of confusion that often exists for developers regarding JavaScript’s this keyword. I mean, is this really this, or is it something else entirely? Or is it undefined?

>As JavaScript coding techniques and design patterns have become increasingly sophisticated over the years, there’s been a corresponding increase in the proliferation of self-referencing scopes within callbacks and closures, which are a fairly common source of “this/that confusion”.

https://javascriptissexy.com/understand-javascripts-this-wit...

>Understand JavaScript’s “this” With Clarity, and Master It

>(Also learn all the scenarios when this is most misunderstood.)

>The this keyword in JavaScript confuses new and seasoned JavaScript developers alike. This article aims to elucidate this in its entirety. By the time we make it through this article, this will be one part of JavaScript we never have to worry about again. We will understand how to use this correctly in every scenario, including the ticklish situations where it usually proves most elusive.

https://dev.to/joelnet/rethinking-javascript-the-complete-el...

>Rethinking JavaScript: The complete elimination and eradication of JavaScript's this.

>If this is so difficult to reason about, why don't we just stop using it? Seriously. Why. don't. we. just. stop. using. it.?

>If you have read How I rediscovered my love for JavaScript after throwing 90% of it in the trash, then you won't be surprised when I say I am throwing this away. this is gone. goodbye. this won't be missed.

>With functional JavaScript, you will almost never see this. I say almost never because even though your code doesn't contain this, you have little control over 3rd party libraries. Popular libraries like React, jQuery, eventemitter2 and many others will force this down your throat.

>Here are some examples of how libraries force us to use this.

[...]

https://softwareengineering.stackexchange.com/questions/3060...

>Why doesn't ES6 have thin-arrow functions?

>See the proposal to add arrow functions:

http://wiki.ecmascript.org/doku.php?id=harmony:arrow_functio...

[That link is broken but this one works: https://tc39wiki.calculist.org/es6/arrow-functions/ ]

>What it says is:

>However, we don’t want CoffeeScript’s ->, it’s confusing to have two arrows and dynamic this binding is an oft-fired footgun.

That's right: the original fat arrow proposal championed by Brendan Eich himself literally called "dynamic this binding" an "oft-fired footgun", citing it as the rationale to justify the design of fat arrow functions. That comes directly from the horse's mouth. Do you really disagree with Brendan Eich on that point?

More interesting discussion about this and that:

Douglas Crockford on Fat Arrow Functions in JavaScript (yuiblog.com)

https://news.ycombinator.com/item?id=3780367

What is the meaning of this?

https://yuiblog.com/blog/2012/03/30/what-is-the-meaning-of-t...

>JavaScript is an amalgam of good parts and bad parts. Its best parts came from Self (prototypes) and Scheme (lexically scoped nested functions). But the interaction of those two very good parts produced some bad parts.

>When a function is called with the function invocation pattern, its this is not bound to the outer function's this as we would hope, but is instead bound to the global object, which is horrible. (ES5/strict binds the inner function's this to undefined, which is much less wrong than binding the global object, but is still not right.) The workarounds for this include the use of bind functions and riddles like

>var that = this;

I could go on. There are literally THOUSANDS of blog posts by people who got screwed by "this", and then posted about it to warn other people not to make the same mistake they did.

Re:Is there any code in Firefox (as of 2020) that comes from... by goto11 on Saturday March 28, 2020 @10:46AM (#22711422)
It has nothing to do with dynamic binding. "this" has lexical scope just like regular parameters. I agree 'this' is confusing, but you are making it sound more mysterious than it is. It is just some syntactic sugar around an implicit first parameter.
Re:Is there any code in Firefox (as of 2020) that comes from... by DonHopkins on Saturday March 28, 2020 @02:27PM (#22713173)
Nope. "this" is formally defined as a keyword in the JavaScript syntax, not a variable, not a property name, not an identifier, and not syntactic sugar, since there is no source level transformation you can make that behaves the same (like with C++, the way CFront translated "this" into an actual first parameter). JavaScript's "this" is magic, that's why it has to be a keyword, not a variable.

It looks like a variable, and it kind of but not really behaves like an implicit first parameter in some circumstances, but that's not really what's going on at all. And that is the danger, and source of misunderstanding and bugs: it looks like something that it's not.

For one thing, you can't assign to "this" like a variable. For another thing, "this" doesn't show up in "arguments" (which is also magic). If you think "this" is not mysterious and just a normal but implicit argument, you don't really understand it.

Which is my point: "this" is such a terribly designed language feature that even experienced JavaScript programmers misunderstand it, and it causes subtle hard to find bugs, even for experienced JavaScript developers. It's not just mysterious, it's dangerous.

https://books.google.nl/books?id=4RChxt67lvwC&pg=PA169&lpg=P...

>JavaScript: The Definitive Guide

>Note that this is a keyword, not a variable or property name. JavaScript syntax does not allow you to assign a value to this.

>Unlike variables, the this keyword does not have a scope, and nested functions do not inherit the this value of their caller. [...]

Here is how "this" is explicitly defined as a keyword in the JavaScript BNF grammer, in this example as the very first option of PrimaryExpression. Definitely not a variable or Identifier. Quite magic. No other "variable" name is defined as a top level PrimaryExpression. "this" is very special.

https://tomcopeland.blogs.com/EcmaScript.html

    PrimaryExpression ::= "this"
                        | ObjectLiteral
                        | ( "(" Expression ")" )
                        | Identifier
                        | ArrayLiteral
                        | Literal
You can even ask devtools for its opinion:

    >var this = 1;
    VM2547:1 Uncaught SyntaxError: Unexpected token 'this'
Re:Is there any code in Firefox (as of 2020) that comes from... by minitech on Sunday March 29, 2020 @11:18PM (#22724932)
When people say it behaves like an implicit first parameter, they’re not claiming it literally is a parameter/variable. Of course it’s a keyword. Of course you can’t assign to it. You’re writing long rebuttals to made up arguments.

You’re also misusing terminology by saying `this` is “dynamically scoped” (it does not have dynamic scope[1], that would be terrible) when documents you’re quoting say “dynamically bound”. The difference is important, which is why three people have corrected you on that now.

[1] https://en.wikipedia.org/wiki/Scope_(computer_science)#Dynam...

Re:Is there any code in Firefox (as of 2020) that comes from... by DonHopkins on Monday March 30, 2020 @04:21PM (#22731902)
So do you agree with goto8 when he says ""this" has lexical scope just like regular parameters" and "Nevertheless, scope wise it behaves like an implicit parameter with lexical scope"?

Explain just how "this" is lexically scoped, what "lexically scoped" means, and then explain why they had to add fat arrow to the language, if "this" is "just like regular parameters", please?

If "this" is lexically scoped, then why can call and apply change it at runtime?

And how do explain this stackexchange discussion, which directly addresses and answers the question? The detailed answer "yes" got five votes and was accepted. The other answer "no" got one vote and was not accepted. What's your answer?

https://softwareengineering.stackexchange.com/questions/3961...

Question> Is `this` in JavaScript an example of dynamic scoping?

Accepted Answer> To be clear, JavaScript does not, in fact, have dynamic scope. It has lexical scope. Plain and simple. But the this mechanism is kind of like dynamic scope.

>The key contrast: lexical scope is write-time, whereas dynamic scope (and this!) are runtime. Lexical scope cares where a function was declared, but dynamic scope cares where a function was called from.

>Finally: this cares how a function was called, which shows how closely related the this mechanism is to the idea of dynamic scoping.

And you ironically wrote:

>(it does not have dynamic scope[1], that would be terrible)

Whatever you call it and however you define dynamic scope, the dynamic way "this" behaves IS terrible, and undeniably causes lots of easy to make, hard to diagnose bugs. That is why Brendan Eich called it a "footgun". That was my point, and that was why they had to add fat arrow to the language.

Re:Is there any code in Firefox (as of 2020) that comes from... by goto11 on Monday March 30, 2020 @05:52PM (#22732615)
Unfortunately, people voting on StackOverflow are not always correct. If you want the correct answer without guessing, you can check the ECMAScript spec itself:

8.3.2 GetThisEnvironment ( )

The abstract operation GetThisEnvironment finds the Environment Record that currently supplies the binding of the keyword this. GetThisEnvironment performs the following steps:

    1. Let lex be the running execution context’s LexicalEnvironment.
    2. Repeat
        a. Let envRec be lex’s EnvironmentRecord.
        b. Let exists be envRec.HasThisBinding().
        c. If exists is true, return envRec.
        d. Let outer be the value of lex’s outer environment reference.
        e. Let lex be outer.
NOTE The loop in step 2 will always terminate because the list of environments always ends with the global environment which has a this binding.

Source: http://www.ecma-international.org/ecma-262/6.0/#sec-getthise...

This is pretty unambiguous. The "this" binding is resolved in the lexical scope, not the dynamic scope.

Re:Is there any code in Firefox (as of 2020) that comes from... by minitech on Monday March 30, 2020 @07:51PM (#22733429)
> So do you agree with [goto11 that] ""this" has lexical scope just like regular parameters" and "Nevertheless, scope wise it behaves like an implicit parameter with lexical scope"?

Yes.

> Explain just how "this" is lexically scoped, what "lexically scoped" means, and then explain why they had to add fat arrow to the language, if "this" is "just like regular parameters", please?

`this` is lexically scoped* because the function it belongs to is determined by where it appears in the code.

Fat arrow was added to the language with this difference because it’s useful to have a function without its own `this`.

> If "this" is lexically scoped, then why can call and apply change it at runtime?

It’s always set at call time. Not a matter of scope. (Parameters: also have values determined at call time, also lexically scoped.)

  function a() { return this; }
  let obj = {a};
  obj.a() === obj
> And how do explain this stackexchange discussion, which directly addresses and answers the question? The detailed answer "yes" got five votes and was accepted. The other answer "no" got one vote and was not accepted. What's your answer?

The answer is wrong despite its votes. The comment on it by JacquesB is correct: “This is confusing values and variables. this cares cares how a function is called the same way parameters care how a function is called - they get their value at runtime when the function is called. But the scope of all variables (including this) is lexical and not dynamic.”

> Whatever you call it and however you define dynamic scope, the dynamic way "this" behaves IS terrible, and undeniably causes lots of easy to make, hard to diagnose bugs. That is why Brendan Eich called it a "footgun". That was my point, and that was why they had to add fat arrow to the language.

I disagree, but am mostly here to argue against objectively wrong information rather than opinions.

* in contrast to dynamically scoped. In JavaScript it’s also common to use “lexical scope” in contrast to “function scope” to distinguish `let`/`const` vs. `var`. In the JavaScript spec, the lexical thisMode refers to where the (arrow) function appears, not the position of the `this`.

Re:Is there any code in Firefox (as of 2020) that comes from... by goto11 on Saturday March 28, 2020 @03:25PM (#22713679)
Nevertheless, scope wise it behaves like an implicit parameter with lexical scope. It just muddies the issue to talk about dynamic scope.
Re:Is there any code in Firefox (as of 2020) that comes from... by DonHopkins on Sunday March 29, 2020 @08:42PM (#22724173)
Dude or dudess, "this" absolutely does not behave in any way like it is lexically scoped, in any sense of the term.

Reality check: Are we even talking about the same language? I'm talking about JavaScript. Which language are you talking about, C++? If you're not talking about JavaScript, then you replied to the wrong comment. Or are you just trolling and gaslighting, because you were offended by the Trump reference? I'll give you the benefit of the doubt that you're also referring to JavaScript, and that you sincerely believe what you say, because you need to change your beliefs.

Please go read any elementary JavaScript tutorial, or any of the thousands of blog posts by people who got screwed by accidentally mis-understanding for a moment and mistakenly thinking that "this" was lexically scoped, then got burnt, but learned from the experience, and wanted to share with everyone else what they learned by shooting themselves with an "oft-fired footgun": "this" is dynamically scoped, and changes meaning at runtime, regardless of the surrounding lexical environment in which it was defined, UNLESS you use fat arrow functions, which were specifically designed to work around that problem.

If "this" behaved like an implicit parameter with lexical scope, then why did they bother adding fat arrow functions to the language as an afterthought, to work around the problem you don't seem to believe exists?

One more time, I will quote the rationale section of Brendan Eich's fat arrow proposal:

https://tc39wiki.calculist.org/es6/arrow-functions/

>"dynamic this binding is an oft-fired footgun" -Brendan Eich, ES6 Arrow Functions Proposal

If you're right, then Brendan Eich, Douglas Crockford, Anders Hejlsberg, many other expert designers and programmers of JavaScript and TypeScript, and a whole lot of other people, are also extremely confused:

https://www.forumone.com/ideas/typescript-application-scale-...

>TypeScript borrows some features from the upcoming ECMAScript 6 specification, too. There is convenience syntax for day-to-day programming tasks, such as the arrow function, borrowed from CoffeeScript. The arrow function, which looks like this: (foo, bar) => baz, is shorthand notation for (function (foo, bar) { return baz; }).bind(this). This automatically captures the current value of “this” in scope, which is more often than not what you want. The proposal even states “dynamic this binding is an oft-fired footgun.”

http://jsnext.blogspot.com/2012/07/arrow-functions.html

>Arrow Functions are lexically bound to the 'this' of where it is declared. In other words, when an Arrow Function is declared, whatever the scope is at that time, that is 'this'. [...] Why add Arrow Functions? Why add this? We already understood what was going on... so why change it? I think that Brendan Eich has provided a great list of reasons ('Rationale' section): [...] However, we don’t want CoffeeScript’s ->, it’s confusing to have two arrows and dynamic this binding is an oft-fired footgun.

What exactly do you believe Brendan Eich meant by "dynamic this binding"? How can "this" be dynamically bound, yet behave "like an implicit parameter with lexical scope" (as you wrongly claim) at the same time?

Is Brendan Eich and everyone else in the JavaScript and TypeScript communities mistaken, and they foolishly added fat arrow functions to JavaScript for no reason, but nobody pointed out that embarrassing mistake until you came along?

If you're right, then you're barking up the wrong tree by arguing with me about it, so by all means, get on Twitter and tell Brendan Eich himself, ASAP! Your argument is with him and everyone else, not me. Maybe it's not too late to turn that ship around, but in my opinion it's already sailed.

But if you're wrong, then you probably have a lot of bugs to fix in your code, and should stay off Twitter.

If you truly believe in your heart of hearts that "this" is lexically scoped, you have definitely proven my and Brendan's point that "this" is a terrible "oft-fired footgun" that causes lots of deep confusion and insidious misunderstanding: just take a step back and look at how sure you are of yourself. Because "this" is certainly more mysterious and dangerous than YOU believe it is.

Re:Is there any code in Firefox (as of 2020) that comes from... by goto11 on Monday March 30, 2020 @03:10AM (#22725849)
Regular JavaScript functions work as if there is an implicit "this" parameter (which gets the value from the left-hand side of the call expression rather than the argument list). Fat-arrow function on the other hand does not change "this", which means the "this" binding inside a fat-arrow function is the one from the containing scope. But in both cases the scope of the "this" binding is lexical.

Dynamic scope means something different. Dynamic scope means that a variable binding from the call site is visible in a called function and down the call stack. This is not how "this" works. The "this" binding at the call site is never visible inside the called function, unless the called function happen to be nested inside the same lexical scope.

"this" is confusing because it gets rebound at every call, even if the function is not called using dot expression. But it is not because of dynamic scoping.

Re:Is there any code in Firefox (as of 2020) that comes from... by saagarjha on Saturday March 28, 2020 @03:11AM (#22709722)
> C++ doesn't have a virtual machine

C++ is designed to compile to an implementation of an abstract virtual machine defined by the standard.

Re:Is there any code in Firefox (as of 2020) that comes from... by DonHopkins on Saturday March 28, 2020 @03:30AM (#22709779)
C++ certainly doesn't have a concrete virtual machine in the way JavaScript does, and C++'s abstract virtual machine certainly doesn't expose as many irrelevant implementation details of that virtual machine as JavaScript does. JavaScript's abstractions are much leakier than C++'s.

https://en.wikipedia.org/wiki/Leaky_abstraction

https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-a...

Don't get what I mean by leaky abstractions? Take non-fat-arrow functions for example. They're more expensive than fat-arrow functions, because they have a "prototype" property. And that's used to IMPLEMENT JavaScript's weird quirky form of object oriented programming, by giving you yet another way to call that function with "new" to create an object using that prototype, in a way that makes it a dangerous mistake to call that function the normal way without "new" (by sorta working on the surface usually without throwing an error, but causing deep subtle hard to diagnose bugs).

That is yet another double barreled footgun, thanks to a leaky abstraction with functions and "new": mistakenly calling a JavaScript class directly instead of using "new", or mistakenly calling "new" on a non-class function or fat arrow function, which doesn't have a prototype and can't be used as a class. Non-fat-arrow functions and "new" are like a footgun whose barrel is bent around aiming at the head of person who's shooting it. Fat-arrow functions don't solve the problem or eliminate the footgun, they merely add another barrel to the gun, aimed directly at your foot, too.

So if you can't directly call or apply a class function that has a prototype like a normal function, then why the hell is it a function anyway, instead just being a class like most other oop languages have, and why the hell does that irrelevant feature of functions having an optional prototype force that overhead on ALL the other functions in the system, whether or not they need it, even if you're using purely functional programming without objects?

That was one of the original rationals for fat arrow functions, as well as papering over the dynamic "this" binding mistake: to get rid of the overhead of the function prototype link, since non-class-constructor functions were so predominantly common. But they didn't bother to fix the obnoxious quirk about overloading functions with behaving like classes, but having to call them differently with "new", instead of simply having classes that were not callable functions, and being able to support multiple constructors with different names and signatures, like so many other object oriented programming languages do (but which JavaScript can't support, since class === function === constructor, there can only be one constructor per class by definition).

Conflating functions and classes and constructors is just insane, a pointless mistake and implementation detail with no upside and many downsides. That's what I call a functionally classic leaky abstraction. ;)

https://news.ycombinator.com/item?id=3780748

>mattbriggs on Mar 31, 2012 | parent | favorite | on: Douglas Crockford on Fat Arrow Functions in JavaSc...

>the this keyword still works exactly the same, just a terse syntax for functions and for function binding to the current scope.

>currently, function(){} is the exact same as the proposed ()->{}, and (function(){}).bind(this) is the exact same as ()=>{}

>starwed on Mar 31, 2012 [-]

>This is not just about syntax. Unless using bind somehow grants the mentioned property that

>>"Fat arrow functions do not have prototype properties, which makes them cheaper to make. They are immutable."

[That was quoting Douglas Crockford: https://yuiblog.com/blog/2012/03/30/what-is-the-meaning-of-t... ]

>mattbriggs on Mar 31, 2012 [-]

>granted, but that sounds more like a micro optimization rather then significantly changing the behavior of the language

Perl originally had the exact same problem of leaky abstractions, only much much worse. The language design was deeply defined by nothing more than the one implementation of the Perl interpreter itself. There was no "abstract virtual machine" design written down. There was only the source code to the one existing implementation of Perl.

You had to understand many trivial details about how that one Perl interpreter just happened to be implemented, in order to truly understand Perl. (Try explaining Perl references without making all kinds of nuanced excuses and implicit references to how the Perl interpreter itself works.)

It took Perl (or whatever the kids are calling it these days) decades and decades to dig its way out of that hole, and by the time they did, it was irrelevant. JavaScript got a lot luckier.

Re:Is there any code in Firefox (as of 2020) that comes from... by rienbdj on Saturday March 28, 2020 @04:45AM (#22709986)
I've written large js projects without using 'this'. Crisis averted, world saved.
Re:Is there any code in Firefox (as of 2020) that comes from... by joyfulmantis on Saturday March 28, 2020 @01:41AM (#22709475)
"Eschew flamebait. Don't introduce flamewar topics unless you have something genuinely new to say. Avoid unrelated controversies and generic tangents."

"Please don't use Hacker News for political or ideological battle. That destroys the curiosity this site exists for."

[dead]
Re:Is there any code in Firefox (as of 2020) that comes from... by joyfulmantis on Saturday March 28, 2020 @02:11AM (#22709560)
I was not referring to what you said about JavaScript, but rather your inclusion of a unrelated, unnecessary and highly polarizing political tangent.
Re:Is there any code in Firefox (as of 2020) that comes from... by DonHopkins on Saturday March 28, 2020 @02:33AM (#22709619)
I'm sorry, I didn't think it was controversial that Trump did that kind of stuff, and it made a perfect metaphor. But even if you disagree about Trump, I think you can still understand the metaphor about JavaScript fat arrow functions. Can you think of a better metaphor?

Edit: I added "(or Obama)" for people who are offended by me pointing out what everyone knows about Trump.

Re:Is there any code in Firefox (as of 2020) that comes from... by saagarjha on Saturday March 28, 2020 @03:00AM (#22709695)
> Can you think of a better metaphor?

One that doesn’t involve politics?

Re:Is there any code in Firefox (as of 2020) that comes from... by DonHopkins on Saturday March 28, 2020 @03:02AM (#22709700)
Programming language design IS politics. Especially JavaScript. How do you think it got its name?
Re:Is there any code in Firefox (as of 2020) that comes from... by saagarjha on Saturday March 28, 2020 @03:09AM (#22709717)
Not that kind of politics.
Re:Is there any code in Firefox (as of 2020) that comes from... by at_a_remove on Saturday March 28, 2020 @03:31AM (#22709784)
Many of us are trying to escape "Trump Derangement Syndrome" which has become infectious almost everywhere else.