7 ms·
is this because you think having one dynamically scoped variable is clearer than having 0?
by anonymoushn 7y ago
is this because you think having one dynamically scoped variable is clearer than having 0?
- austincheney 7y agoI think arrow functions are less clear because they are always anonymous functions. Anonymous functions complicate stack traces and performance profiles.
- DonHopkins 7y agoGuido 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 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 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. [...]
- m1sta_ 7y agoThere 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.
- DonHopkins 7y agoWhat'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.
- saagarjha 7y ago> Anonymous functions complicate stack traces and performance profiles. It depends. Often you can optimize them out.
- rejschaap 7y agoDoesn't that just complicate things even more?
- minitech 7y agoThey 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.
- austincheney 7y agoThat is three examples of assignments. The arrow functions remain anonymous. * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... * https://developer.mozilla.org/id/docs/Web/JavaScript/Reference/Functions/Arrow_functions https://developer.mozilla.org/id/docs/Web/JavaScript/Referen...
- roblabla 7y agoYour 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.
- austincheney 7y agoThe 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.
- DonHopkins 7y agoIt 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!
- joyfulmantis 7y ago"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."
- DonHopkins 7y agoWhat, we can't talk about JavaScript?! At least I didn't mention Brendan Eich's deep and tragic mistaken misunderstanding of equality. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...