6 ms·
No one likes callback hell but I believe they meant that you can just pass a function expression directly. No need to define a named function. It's the differen
by neurotrace 9y ago
No one likes callback hell but I believe they meant that you can just pass a function expression directly. No need to define a named function. It's the difference between:
let doubled = nums.map(x => x * 2)
and this:
def double(x):
return x * 2
doubled = map(double, nums)
(my Python is pretty rusty so maybe there's a better way of doing that)
- takeda 9y agoYou can do the exact same thing in Python, and this is not any new feature: doubled = map(lambda x: x * 2, nums) JS it's just not as explicit with what you're exactly doing.
- gknoy 9y agoIf you want more than a one-line lambda, however, you're in for a rough time, and need to go the route of def foo(): # ... four lines here ... modified = map(foo, items)
- pseudalopex 9y agoWhat's rough about giving a function a name?
- gknoy 9y agoNaming things is one of the hard things in computer science. :) Anonymous functions, when appropriate, let us avoid having to think about that. For example, `f` is a refactoring of an anonymous function: function f (item) { return { // foo properties } } const fooItems = values.map(item => f) Imagine that you have to map over several different collections of items, and generating the lists `foo`, `bar`, and `baz`. You have to either name the functions we pass to map `f`, `g`, and `h` (which I bet our reviewers would hate), or `fooMapFunc`, `barMapFunc`, `bazMapFunc`. It just pollutes the namespace that I have to keep in my head, because I have to wonder "is this used somewhere else?". Moreover, is it _more readable_ to define the helpers first, and then the collections that are made by using them, or to define the pairs (fooMapFunc, fooItems) in sequence? This could easily be felt one way or the other, and both are valid, but leads to code review holy wars. "I feel this is more readable / I feel exactly opposite". For comparison, the anonymous version of this similar operation: const fooItems = values.map((item) => { return { // foo properties } }) const barItems = values.map((item) => { return { // bar properties } }) const bazItems = values.map((item) => { return { // baz properties } }) In this case, the anonymous function is clearly not usable anywhere else, so it's easier to be sure that it's something one can change, and completely removes the chance of holy war over readability of whether to define helper functions together or with their collection.
- pseudalopex 9y agoNaming things is hard because names represent abstractions. Complex abstractions are hard to get right and hard to summarize; widely-used abstractions and names are hard to change. A nested function is a simple abstraction in a narrow scope. Both the abstraction and the name are easy to change, so the name only has to describe what the function does now. When that's hard, it's often because the function does too much, does too little, or belongs somewhere else. Likewise, people arguing about the organization of inner functions is usually a sign the outer function should be refactored. Anonymous functions are appropriate when names would be almost redundant, not when coming up with a name is hard. My editor can show me where a function is used; it can't summarize what a function does. Either way, you have to find where "fooItems" is used to know if you can modify the function. Conversion functions are very easy to name ("itemToFoo"). Idiomatic Python would just use a loop: foo_items = [] for item in values: foo_items.append({ # foo properties })
- crimsonalucard 9y agoThe pythonic way is to use a list comprehension for maps and filters.
- takeda 9y agoyes, but we were talking about passing an anonymous function as an argument and that was the example used.
- pjmlp 9y agoNow try a multi-line one in Python.
- scriptkiddy 9y ago> (my Python is pretty rusty so maybe there's a better way of doing that) return [x*2 for x in nums]
- deleted 9y ago[deleted]
- bobwaycott 9y agodoubled = [x * 2 for x in nums]
- crimsonalucard 9y agoIt's true js is better with anonymous functions. But the design of js (node esp.) requires you to constantly pass these callbacks to do async. Critics of JS are basically claiming that a programming style that overuses anonymous functions as parameters into other functions leads to unreadable and overcomplicated code... hence why python restricts anonymous functions from being over one line long. Typically in programming you don't often encounter the need to pass a multiline anonymous function into another function, it leads to confusing code. Async/await gets rid of this bs all together which is the pythonic way to do async. btw pythonic code for maps or filters is to use list comprehensions so doubled = [x2 for x in nums] or if you want to use a anon function: doubled = [(lambda y: y2)(x) for x in nums]
- neurotrace 9y agoI'd say that anyone who's complaining about callback hell isn't up-to-date with the JS world. Promises have fixed this problem and, as you pointed out, async/await make it even nicer. In my experience (I write mostly JS but also a lot of C# and, not as much, Rust), passing functions around is very easy to read and reason about. Functional programming "Just Makes Sense™" to me. I think it's just an exposure thing. Many people find Python's significant whitespace cleaner. I disagree but I promise you it's because I haven't spend much time with it. If I wrote a lot more Python, I'd probably grow to like it.
- pseudalopex 9y agoPassing around functions is great, but it's easier to read and reason about when the functions have names. I see a lot of complex/nested anonymous functions in JavaScript code, even with promises.
- crimsonalucard 9y agoFirst off, you aren't doing functional programming when you have first class functions or if you use HO functions like map and reduce. Those concepts can exist in imperative programs. The only concept that makes a program functional is immutability. That's it. Functional programming does not make sense to you if you don't understand this. >I'd say that anyone who's complaining about callback hell isn't up-to-date with the JS world. Promises have fixed this problem and, as you pointed out, async/await make it even nicer. The latest node api still uses callbacks. Promises haven't fixed this problem, it's just a bandaid on stab wound. Async/await is the proper way to deal with this problem and python supports it so there's no upside for node in this area.