News for hackers. Stuff that matters.
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?