7 ms·
Not JavaScript. Cool kids never write “function” any more, it’s all arrow functions. You can search for const, which will typically work, but not always (could
by CGamesPlay 2y ago
Not JavaScript. Cool kids never write “function” any more, it’s all arrow functions. You can search for const, which will typically work, but not always (could be a let, var, or multi-const intializer).
- lispisok 2y agoAm I the only one who hates arrow functions?
- spartanatreyu 2y agoI did, until I used them enough where I saw where they were useful. The bad examples of arrow functions I saw initially were of: 1. Devs trying to mix them in with OOP code as a bandaid over OOP headahes (e.g. bind/this) instead of just not using OOP in the first place. 2. Devs trying to stick functional programming everywhere because they had seen a trivial example where a `.map()` made more semantic sense than a for/for-in/for-of loop. Despite the fact that for/for-in/for-of loops were easier to read for anything non-trivial and also had better performance because you had access to the `break`, `continue` and `return` keywords.
- mewpmewp2 2y agoAnother benefit of using for instead of array fns is that it is easy to add await keyword should the fn become async. But many teams will have it as a rule to always use array fns.
- jappgar 2y agoThat gives you have the option of making it serially async but not parallel, which can be achieved easily using Promise.all in either scenario.
- adregan 2y agoAs an aside: It’s way less ergonomic, but you likely want `Promise.allSettled` rather than `Promise.all` as the first promise that throws aborts the rest.
- wruza 2y agoIt doesn’t really abort the rest, it just prioritizes the selection of a first catch-path as a current continuation. The rest is still thenable, and there’s no “abort promise” operation in general. There are abort signals, but it’s up to an async process to accept a signal and decide when/whether to check it.
- adregan 2y agoAdmittedly, I was being a bit hand-wavy and describing a bit more of how it feels rather than the way it is (I'm perpetually annoyed that promises can't be cancelled), but I was thinking of the code I've seen many times across many code bases: let results; try { results = await Promise.all(vals.map(someAsyncOp)) } catch (err) { console.error(err) } While you could pull that promises mapping into a variable and keep it thenable, 99% of the time I see the above instead. Promises have some rough edges because they are stateful, so I think it might be easier to recommend swapping that Promise.all for an Promise.allSettled, and using a shared utility for parsing the promise result. I consider this issue akin to the relationship between `sort`, `reverse`, `splice`, the mutating operation APIs, and their non mutating counterparts `toSorted`, `toReversed`, `toSpliced`. Promise.all is kind of the mutating version of allSettled.
- throwaway2037 2y ago> also had better performance because you had access to the `break`, `continue` and `return` keywords. This is a great point. One more: Debugging `.map()` is also much harder than a for loop.
- medstrom 2y agoI feel there are a few ways to invoke .map() in a readable way and many ways that make the code flow needlessly indirect. Should be a judgment call, and the author needs to be used to doing both looping and mapping constructs, so that they are unafraid of the bit of extra typing needed for the loop.
- ndnxncjdj 2y agoI very much prefer the way scoping is handled in arrow functions.
- nosianu 2y agoA simple heuristic I use is to use arrow functions for inline function arguments, and named "function" functions for all others. One reason is exactly what the subject of discussion is here, it's easier to string-search with that keyword in front of the name, but I don't need that for trivial inline functions (whenever I do I make it an actual function that I declare normally and not inline). Then there's the different handling of "this", depending on how you write your code this may be an important reason to use an arrow function in some places.
- turboponyy 2y agoI like them because it reinforces the idea that functions are just values like any other - having a separate keyword feels like it is inconsistent.
- 0xfffafaCrash 2y agoMoreover the binding and lexical scope aspects supported by classic functions are amongst the worst aspects of the language. Arrow functions are also far more concise and ergonomic when working with higher order functions or simple expressions The main thing to be wary of with arrow functions is when they are used anonymously inline without it being clear what the function is doing at a glance. That and Error stack traces but the latter is exacerbated by there being no actual standard regarding Error.prototype.stack
- mewpmewp2 2y agoWhy do you want to reinforce that idea? To me arrow functions mostly just decrease readability and makes them blend in too much, when it should be important distinction what is a function and what is not.
- nsonha 2y ago> should be important distinction what is a function and what is not code is to express logic clearly to the reader. We should assess it for that purpose, before assess for any derivative, secondary concern such as whether categories of things in code (function etc) visually pops out when you use some specific tool like vim, or grep. There are syntax highlighters for a reason. And maybe if grep sucks with code then build the proper tool for code searching, instead of writing code after the tool.
- turboponyy 2y agoNot to be dismissive, but because I like it - it just sits right with me.
- benrutter 2y agoI'm not a javascript programmer, but I really like the arrow pattern from a distance exactly because it enforces that idea. My experience is that newcomers are often thrown off and confused by higher order functions. I think partly because, well let's be honest they just are more confusing than normal functions, but I think it's also because languages often bind functions differently from everything else. `const cool = () => 5` Makes it obvious and transparent, that `cool' is just a variable where as: `function cool() {return 5}` looks very different from other variable bindings.
- crabmusket 2y agoI don't like using them everywhere, but they're very handy for inline anonymous functions. But it really pains me when I see export const foo = () => {} instead of export function foo() {}
- creesch 2y agoThank you, that's something I also never have understood myself. For inline anonymous functions like callbacks they make perfect sense. As long as you don't need `this`. But everywhere else they reduce readability of the code with no tangible benefit I am aware of.
- berkes 2y agoI wish javascript had a built-in or at least (defacto) default linter. Like go-fmt or rust fmt. Or clippy even. One that could enforce these styles. Because not only is the export const foo = () {} painful on itself, it will quite certainly get intermixed with the function foo() {} and then in the next library a const foo = function() {} and so on. I'd rather have a consistently irritating style, than this willy-nilly yolo style that the JS community seems to embrace.
- throwitaway1123 2y agoESLint and Prettier are the de facto default linter/formatter combo in JS. There are rules you can enable to enforce your preferred style of function [1][2]. [1] https://eslint.org/docs/latest/rules/func-style https://eslint.org/docs/latest/rules/func-style [2] https://eslint.org/docs/latest/rules/prefer-arrow-callback https://eslint.org/docs/latest/rules/prefer-arrow-callback
- berkes 2y agoThey are miles away from `gofmt` or `rust fmt` or `cargo clippy` and so on. It's not opinionated, but requiring you to form your own opinion or at least choose from a palette of opinions. It requires effort to opt-in rather than effort to opt-out. The community doesn't frown on code that's not adhering to the common standard or code that doesn't pass the "out of the box" linter. So, if I have a typescript project with a tree of some 20 dependencies (which is, unfortunately, a tiny project), I'll have at least five styles of code when it browse through it. Some JS, some TS, some strictly linted with "no-bikeshedding", some linted with configs that are bigger than the codebase itself. Some linted with outdated. Many not linted at all. It's really a mess. Even if each of the 20 dependencies themselves are clean, beauties, the whole is an inconsistent mess.
- nsonha 2y agowhy the need to pronounce arbitrary preferences, who cares?
- ajuc 2y agoI'm of the opinion that giving a global name to an anonymous function should result in a compilation error.
- supriyo-biswas 2y agoYou can still search for `<keyword> = \(.*\) => `, albeit it's a bit cumbersome.
- post-it 2y agoAll you need is `<keyword> =` Really, all you need is `<keyword>` and if the first result is a call to that function, just jump to its definition.
- spartanatreyu 2y agoExactly. Just search the definition. Any time that a function doesn't have a definition, it's never the target of a search anyway.
- troupo 2y agoAll you need is a tool that actually understands the language. It's 2024 and HN still suggests using regular expressions to search through a code base.
- db48x 2y agoI both agree and disagree with this. I was very careful about how I phrased my comment. Languages can gain points by being greppable, and they can gain points by having a well–implemented mode for my favorite editor, and they can also gain points by having a well–implemented language server. They can do all three to gain the most points (and of course there are many other ways to gain or lose points; this is just one tiny aspect of language design), but they don’t have to. And nobody should try to force every language designer to shave the yak of writing an Emacs mode or a Language Server. And sometimes you just want to improve some random piece of software written in a language that you’ve never used before, without having to shave a bunch of yaks to get the language server installed. Sometimes all you have is grep and you’ll want to be able to use it on this weird new language.
- lukan 2y agoRegex is a universal tool. Your special tool might not work on plattform X, fails for edge case - and you generally don't know how it works. With regex or simple string search - I am in control. And can understand why results show up, or investigate when they don't, but should.
- spartanatreyu 2y agoYes JavaScript. You can search for both: "function" and "=>" to find all function expressions and arrow function expressions. All named functions are easily searchable. All anonymous functions are throw away functions that are only called in one place so you don't need to search for them in the first place. As soon as an anonymous function becomes important enough to receive a label (i.e. assigning it to a variable, being assigned to a parameter, converting to function expression), it has also become searchable by that label too.
- CGamesPlay 2y agoThe => is after the param spec, so you’re searching for foo.*=> or something more complex, but then still missing multiline signatures. This is very easy to get caught by in TypeScript, and also happens when dealing with higher-order functions (quite common in React).
- spartanatreyu 2y agoWhy are you searching for foo.=> Are you searching through every function, or functions that have a very specific parameter? And whatever you picked, why? --------------------------------------------------------------- - If you're searching for every function, then there's no need to search for foo.=>, you only need to search for function and =>. - If you're searching for a specific parameter, then just search for the parameter. Searching for functions is redundant. --------------------------------------------------------------- Arrow function expressions and function expressions can both be named or anonymous. Introducing arrow functions didn't suddenly make JavaScript unsearchable. JavaScript supported anonymous functions before arrow function expressions were introduced. Anonymous functions can only ever be: - run on the spot - thrown away - or passed around after they've been given a label Which means, whenever you actually want to search for something, it's going to be labelled. So search for the label.
- pjerem 2y agoYes but that’s an anti pattern. Arrow functions aren’t there to look cool, they’re how you define lambdas / anonymous functions. Other than that, functions should be defined by the keyword.
- bobbylarrybobby 2y agoFunctions and arrow functions have an important difference: arrow functions do not create their own `this`. If you're in a context where a nested function needs to maintain access to the outer function’s `this`, and you don't want to muck with `bind` or `call`, then you need an arrow function.
- wiseowise 2y agoHow is that an anti-pattern? > Other than that, functions should be defined by the keyword. Says who?
- lukan 2y agoAll the wise ones. Well, except for you maybe. Serious arguments would be: - readability - greppability
- lukan 2y ago(It wasn't an insult, but a joke on the username)
- tylerhou 2y agoAs of a few years ago (not sure about now) the backtrace frame info for anonymous functions were far worse than ones defined via the function keyword with a name.
- hansworst 2y agoAnonymous functions don't have names. This makes it much harder to do things like profiling (just try to find that one specific arrow function in your performance profile flame graph) and tracing. Tools like Sentry that automatically log stack traces when errors occur become much less useful if every function is anonymous.
- albedoa 2y agoI want to talk to the developer who considers greppability when deciding whether to use the "function" keyword but requires his definitions to be greppable by distancing them from their call locations. I just have a few questions for him.
- Pxtl 2y agoYou can still look for `(funcname)\s*=` can't you? I mean it's not like functions get re-declared a lot.