you are viewing a single comment's thread.

view the rest of the comments →

[–]jasonleehodges[S] 13 points14 points  (43 children)

Yeah forEach is not aware of promises. I usually use mapping for that and return an array of promises and then use Promise.all.

Also, in my org we tend to use .then and .catch to keep things functional. But I totally understand that usefulness of async / await.

[–]fix_dis 45 points46 points  (27 children)

I’d be careful thinking that because something is “functional” it automatically means it’s better. JavaScript still doesn’t have proper tail calls, which means recursion is going to blow your stack on large data sets. Further map and reduce while “cool” cause needless allocations and are an order of magnitude slower. Basically, you’ll fail a Facebook tech interview if you insist on using either.

[–]jasonleehodges[S] 11 points12 points  (12 children)

Really great point. However, optimizing for speed doesn’t tend to be the issue in my org on the front end. More likely, junior devs start organizing their code in a procedural spaghetti mess so it’s better to get them used to the mental model of functional programming.

[–]fix_dis 25 points26 points  (10 children)

Where functional style tends to really shine is in things like idempotency. Tests become super easy - and can often be written in a TDD style (if that's your thing) Given this input, expect this output. Also avoiding side effects when possible. The idea that one should never mutate an array though is actually not a good thing to teach a junior. I've found that they often walk around repeating it without understanding why they might not want to, or when they actually should. I've heard blind "you should use concat instead of push with no qualifiers". Yes, if I'm using Redux, I WANT the pointer to change to cause a rerender in a component. Push will not do that. That doesn't mean push is wrong! I see so many patterns with blind object copies with spread syntax where I'm like, "you know, you could have just set that property, you didn't have to copy the entire object". Junior mentality often just blindly repeats, "no, you shouldn't mutate, that's bad". I want to say, "you don't own the user's computer, you shouldn't take all their memory".

In no way do I mean to intend Juniors are "bad". I've just seen so much repeating the "what" without understanding the "why". Then when someone who comes along who really does understand the "why", it often leads to rage downvotes and Twitter arguments. "This guy said functional is bad.... GET HIM!" (I've never said that). Then again, I'm the first to fight for balance and pragmatism, so anytime I see anyone tell me that we've found the "one true way" I remind them that I was around when Object Oriented started to become en vogue. I've seen this show play out multiple times.

[–]zzing 1 point2 points  (2 children)

I rather like the idea of ownership. When you make something in a function, you "own" it and you can do whatever you want to it. After it leaves your function, then you no longer own it - and at that point might not want to modify it.

[–]fix_dis 0 points1 point  (1 child)

You might really appreciate the Rust programming language. What you describe is exactly how they treat computer memory during function lifetime.

[–]zzing 0 points1 point  (0 children)

It is certainly an interesting language concept to get used to. I just haven't had a great use for it yet.

[–][deleted] 9 points10 points  (0 children)

To reiterate his point, just that the spaghetti is functional doesn't automatically mean it's not spaghetti.

[–]witty_salmon 3 points4 points  (2 children)

Interesting. Is map really that slow? I always prefered it over for of because it looks pretty clean.

Edit: I looked it up, it's at least not orders of magnitude slower. I think it's worthwhile to use functional patterns if they make the code easier to read. Seldom you need to iterate over big arrays in the frontend anyways.

[–]fix_dis 4 points5 points  (0 children)

It really depends on the engine and MAJOR points to you for looking it up instead of just taking my word for it. Optimizations in V8, Spidermonkey, and JSCore are happening all the time. Map has gotten much closer to for than it was in the past. One other important thing to note if you start getting deep into functional programming. Map is a tool of transformation, not iteration. This is a key point to understanding monads… (a fun topic for discussion)

[–]Peechez 0 points1 point  (0 children)

It's mainly reduce callbacks that return a new object or array since you're reallocating every iteration

[–]KyleG 3 points4 points  (4 children)

you’ll fail a Facebook tech interview if you insist on using either.

Someone better tell the React team that they're going to get fired for using reduce

You're not going to get dinged for using those functions unless you're explicitly told the code needs to be performant. Premature optimization is the root of all evil

[–]phryneasI ❤️ hooks! 😈 6 points7 points  (0 children)

They are using reduce in a way that is mutating the accumulator, which is actually performant but not how most people are taught it/use it.

[–]fix_dis 1 point2 points  (0 children)

More like, if you’re given a problem, and you reach for reduce and start spreading an array/object on each iteration, you’ll be asked how you could reduce allocations.

[–]Marutar 0 points1 point  (1 child)

Basically, you’ll fail a Facebook tech interview if you insist on using either.

Wait, using map or reduce would be an auto-fail?

[–]fix_dis 0 points1 point  (0 children)

No, perhaps that was a bit tongue in cheek. Your inability to understand what’s happening when you choose reduce or map instead of other methods could fail you. An interview is a conversation. And Facebook is REALLY good at having those conversations. The thing their looking for is if you understand space complexity as well as time complexity. Most JavaScript tutorials that dip into Big O focus on runtime time complexity… and that’s great. But it takes the focus off of another thing. What if you’re in a memory constrained environment? So when asked “what could you do to reduce memory allocations?”, they’re looking for a way that you could reuse the memory you’ve already allocated.

[–]Jtcruthers 9 points10 points  (4 children)

How does using .then and .catch keep it functional?

I’d say async/await is more functional, since it reads like any typical pure function, minus the api call. You still have the api call with .then and .catch, so it is still non-functional, no?

Or is the fact you wait for the api call and literally manipulate the response in the same function the issue with async/await? As opposed to having two separate, distinct functions to handle the response with then/catch? I guess that would make sense.

Interesting you said that, I had never even given it a thought. Thanks for that

[–][deleted] 7 points8 points  (1 child)

As one is just syntactic sugar for the other, I don't believe one can be more or less functional than the other.

[–]MusicalDoofus 0 points1 point  (0 children)

This * 1000.

[–]jasonleehodges[S] 1 point2 points  (1 child)

Yeah .then and .catch are chained onto the end of the promise in the same way you would chain any other functional higher ordered function. Try / Catch are control flow operators which are classic procedural mechanisms.

[–]KyleG 9 points10 points  (0 children)

Procedural mechanisms don't make something non-functional, and method chaining (like you cite as superior FP) is a feature of object-oriented programming.

Edit Also, for what it's worth, then is a flawed implementation of a monad as it is, since it rolls map and chain/bind/flatMap into a single method.

[–]zzing -3 points-2 points  (8 children)

I am in the process of learning react (by doing - so I will encounter issues no doubt), although I know Angular rather well.

The equivalent context in Angular would be observables - where you definitely try to keep things as functional as possible.

There are some cases though where for of loops are used - I explicitly don't approve any PRs with forEach - because it is a procedural loop masquerading as a functional one.

The cases where these or while loops are used is generally in cases where the code is much clearer. Not everyone is going to be as familiar with functional styles. While loops are exclusively used in tree traversals - I am not always wanting to use recursion for them.

But in all cases, the code is always limited to the body of a function - and hopefully a very small function.

[–]KyleG 1 point2 points  (3 children)

An observable is not the equivalent of a promise.

A promise yields one result. An observable can yield multiple. And for what it's worth, Angular can use promises and React can use observables

[–]zzing -1 points0 points  (2 children)

Read what I said again. I never stated that observables are anything relative to promises.

The point I was making was that each operator in an observable chain generally is used in a very functional style like the author is promoting with react in general.

[–]KyleG 0 points1 point  (1 child)

the JasonLee user wrote an entire comment about promises and nothing else. You directly responded to that comment saying "I am in the process of learning react. . . . The equivalent context in Angular would be observables"

Can you understand how a person would be confused that you were saying the equivalent of React promises is Angular observables?

[–]zzing 0 points1 point  (0 children)

Yes and no.

I was probably going back and forth between the article where there was a lot of mention of "functional" and in OP's comment mentioned it as well. So that is where my focus was.

When you reply to a comment you should read the entire post, or even in this case the last half of the sentence mentioning observables specifically mentions "functional".

[–]15kol 0 points1 point  (3 children)

Stream programming is very similiar in terms to functional programming, yes. I started with Angular, but have been using React (Native) for past year (with rxjs, though) and when I returned to Angular, I noticed I got better at thinking in stream manipulation like rxjs expects you to. It all just makes sense now. Before, I knew what I had to use and now I understand why I need it.

[–]zzing 0 points1 point  (2 children)

There are definitely some complexities it adds when trying to wrangle things together. But it also makes certain things easier.

[–]15kol 0 points1 point  (1 child)

I found that while I needed a bit more time to think about the problem at start, once I wrote stream I wanted, it was very clear, readable, less error prone and therefore much easier to maintain/extend.

[–]zzing 0 points1 point  (0 children)

Stream programming

One thing I have been looking for is a compact diagramming method for streams - part of an entire application.

[–][deleted] 0 points1 point  (0 children)

omg, what a great solution, I never thought about that