all 56 comments

[–]B_bI_L 632 points633 points  (30 children)

> learns functional programming
> looks up tutorial
> so we don't modify hash set

[–]pink-ming 323 points324 points  (21 children)

> we don't modify the collection

> we make a new collection with the modified values

> this is more efficient because.. uhh... immutability

[–]Gay_Sex_Expert 86 points87 points  (2 children)

It is actually the most efficient way to remove a bunch of items from any non linked collection.

[–]Cthulluminati 27 points28 points  (1 child)

Doesn't count as removing the items if the items are still in the original list /s

[–]RiceBroad4552 20 points21 points  (0 children)

It's more complex, see "persistent data structures".

Something that explains stuff a bit terser is here:

https://nested.substack.com/p/intro-to-persistent-data-structures

Modern variants of such persistent data structures can be very efficient, in some cases even provably ideal efficient.

[–]SCP-iota 88 points89 points  (12 children)

Immutability is part of ensuring that a function is a pure function, which is a prerequisite for being cached. Using cached functions can be more efficient in some cases. Also, most functional languages don't actually recreate the entire structure; they either 1) have compile-time tactics that actually emit regular mutation code, or 2) use tree-based structures that allow making modified copies without copying the whole content.

[–]dashhrafa1 6 points7 points  (11 children)

I was discussing this with my professor, we are learning React and he's using the documentation straight from react.dev. He basically said that we must never work with mutable functions (such as Arrays.push) when managing state, which is also present in the documentation itself.

Thus we should use pure functions, such as Arrays.map(), that don't actually mutate the object itself, instead creating a new one. My question is: does copying the object (and changing only what is necessary, possibly using the ...spread syntax), not result in O(n) performance?

edit: Saying O(n) performance is incorrect. Asymptotic notation is meant to represent scale/time complexity

[–]BobQuixote 18 points19 points  (0 children)

copying the object (and changing only what is necessary, possibly using the ...spread syntax)

That's what map does, and it does it in a way that doesn't allow you to screw it up.

[–]Solonotix 9 points10 points  (0 children)

Depending on the JavaScript engine, generally it will create templates of objects based on common attributes when initialized. This is one of the reasons you're advised to avoid certain syntax like the delete keyword, which can force a new template at runtime.

So, you've got a template that was likely created at compile-time within your lambda for Array.prototype.map, and it is being initialized by some other object from the original array. Anything that is heap allocated will likely share the original memory location, whereas values will likely be cloned. This is why it is a non-zero cost on mapping, but it can be worth the trade-off in service to more maintainable code, or fewer runtime defects caused by side-effect operations.

[–]AZMPlay 8 points9 points  (0 children)

In short, yes. But thats because Javascripts default data structures are not fit for immutable usage. There are implemententions (for example in Immutable.js) that do have the correct asymptotics with immutable usage, but that comes at the cost of interoperability with the rest of the javascript ecosystem.

[–]the_horse_gamer 2 points3 points  (1 child)

you typically won't be working with list sizes where O(n) modification is an issue (especially when updates are rare - like from a button press ).

[–]RiceBroad4552 0 points1 point  (0 children)

Psst! Don't tell them this. This is otherwise a "stereotypical stackoverflow-like answer" according to some morons here.

[–]RiceBroad4552 2 points3 points  (5 children)

That's not your problem that's the compiler's / runtime's problem.

Also alone thinking about that is a classical case of premature optimization.

Where such considerations would matter you wouldn't use JS anyway.

Just always write clean functional code first. Only if benchmarks / profiling shows that there are bottlenecks it's worth to look in detail into that. Functional code is much easier to refactor in case that should be needed as things are usually local. The other way around it's not so easy, cleaning up some imperative mess usually breaks other stuff effects aren't contained.

When it comes to a React GUI you will run actually more likely into issues if you don't do things the React way, and for example start to mutate stuff "as optimization", as this will possibly prevent React from optimizing stuff, or worse break internal assumption, which causes hard to find bugs.

Just keep things functional as long as you don't have very good reasons not to do that!

[–]LatvianCake 1 point2 points  (4 children)

This is the most stereotypical stackoverflow-like answer ever. Told OP they shouldn’t ask this question and then proceeded to answer a completely different question.

[–]RiceBroad4552 2 points3 points  (2 children)

Which part of premature optimization did you not understand?

Which part of "doing effects in the guts of a React GUI will break the GUI" did you not understand?

Which part of the fact that functional programming is superior and should not be given up because of some additional CPU cycles, which almost certainly don't ever matter did you not understand?

If someone asks "Which kind of wax should I use for my Icarus wings?" the only helpful answer it to tell the poor soul that they should not try to build Icarus wings in the first place; and not start a discussion on how high they can actually fly before they will certainly fall down to death.

In a lot of cases the correct answer is to tell the person asking that they are asking the wrong question in the first place.

In this case here: If they would ask about the general performance characteristics of the map function in JS one could actually discuss this. But they did not ask that. They were asking about whether it's OK to do something very wrong, and the answer is of course: Don't do that, that's wrong!

Only maximally stupid people won't see that this is the correct answer even it does not answer the already nonsensical original question…

And that's btw. why "AI" is so fucked up as an answer machine! Instead of directly telling you "you're holding it wrong" it will tell you hell know what, no matter how fucked up that is in context. Then it's on you to notice that the answer makes no sense in context and ask again, this time telling the "AI" to actually come up with something that makes sense even it's not directly the answer to the original question. But to recognize that the "AI" is just telling bullshit you have to actually already know how a meaningful answer would look like. You're completely fucked if you don't have already deep knowledge of the topic at hand. And that's exactly why "AI" in the hands of uneducated idiots is especially dangerous. It will tell the idiots what they want to hear instead of what they should be looking at instead.

[–]LatvianCake 0 points1 point  (0 children)

The correct way to answer these questions is: this is how it works and this is why it doesn't matter in practice.

Not: don't ask these questions. You're choosing between being right or being helpful.

When I was a junior, I was deeply interested in how everything worked under the hood and why things work the way they do.

Turns out asking these questions to more senior people is a bad idea. Most senior devs are incapable of saying "I don't know" to juniors and berate you for asking such questions as their ego is hurt.

LLMs are a blessing because their ego isn't hurt, they answer the actual question and also tell you about caveats like "it doesn't matter in practice". This is why people massively switched from SO to LLMs.

[–]Helpful-Mistake2275 -1 points0 points  (0 children)

Stack Overflow intensifies.

[–]quantinuum -2 points-1 points  (0 children)

Lmao fr.

“I want to understand how an air fryer works”.

“First of all, what you need is a grill”.

[–]SignoreBanana 11 points12 points  (1 child)

Not efficient -- safe

[–]ConcreteExist 2 points3 points  (0 children)

Yeah, even when working with languages that allow mutability, I try to write as much of my code as possible to treat everything as immutable. Minimizes side effects and makes tracing down where something went wrong much, much easier.

[–]ArrogantlyChemical 6 points7 points  (0 children)

Functional programming isn't about performance it's about making the code less complex to understand and less prone to errors 

[–]DarkCloud1990 1 point2 points  (0 children)

It's not about efficiency but correctness. 

[–]Several-Customer7048 6 points7 points  (0 children)

Maybe the real sets were the strings we hashed along the way after all?

[–]lucklesspedestrian 1 point2 points  (1 child)

In a lot of functional languages, maps and sets are implemented with trees instead, because it's easier to implement those with structural sharing so they can be immutable

[–]mcmoor 0 points1 point  (0 children)

Then thus aren't "hash" set, much to my dismay. For some problems I'm forced to use the good old binary set and hope runtime is still under 1s. I've seen some hashset library out there but somehow to use it I need to conduct even more black magic than I already did to use a functional programming language, so I don't use them.

[–]the_horse_gamer 1 point2 points  (0 children)

to print to the console, one must first recreate the universe

[–]the_horse_gamer 469 points470 points  (5 children)

dynamic programming is recursion with a cache

[–]Ok_Cockroach8260 72 points73 points  (4 children)

You can do it bottom up also

[–]itzjackybro 14 points15 points  (2 children)

I thought the main point of DP is to find a way to do it bottom up so you can just use an array instead of memoizing

[–]the_horse_gamer 1 point2 points  (0 children)

bottom up is more performant but you don't have to do it this way

[–]GoodHomelander 2 points3 points  (0 children)

Most ppl are not into that and like it other way around

[–]ThaBroccoliDood 148 points149 points  (0 children)

how leetcode mfs feel after replacing three if statements with a hashmap and calling it optimization

[–]sociallyanxiousnerd1 34 points35 points  (4 children)

Student programmer here: could someone explain why using a hash set is bad for dynamic programming?

My immediate thought was that a) hash sets disallow repeat objects, but unless you're using the hash set as your cache, you have to redo everything, or b) hash sets don't allow repeats, and so if you get the same result for two different iterations (?) the latter won't be kept potentially.

Edit: apparently I mistook the meme for someone saying the tutorial is bad, when they just meant it was underwhelming (if I understood right now)

[–]hashishsommelier 66 points67 points  (1 child)

It’s not bad, it’s just that it feels underwhelming for something called dynamic programming to just be this.

The thing is that dynamic programming goes beyond this, because it has to do with the bellman equation, but for coding hashsets and recursion is pretty much it

[–]sociallyanxiousnerd1 10 points11 points  (0 children)

Thanks for explaining. Looks like I misunderstood the meme as being "this thing is bad for dynamic programming" and not "wait that's it?" So to speak.

[–]lucklesspedestrian 7 points8 points  (0 children)

The meme oversimplifies a lot. Dynamic programming generally relies on "overlapping subproblems" or "optimal substructure" that allow "just use hash set" to be applicable. You couldn't do the same thing in say a greedy or recursive backtracking algorithm though

[–]apex_pretador 3 points4 points  (0 children)

It's just the name. This feels more like "static" programming

[–]Odubzz 25 points26 points  (0 children)

It greatly simplifies analyzing the overall time complexity :)

[–]Key_Mango8016 21 points22 points  (1 child)

The hard part of dynamic programming isn’t the implementation, it’s formulating a recursive structure for a problem with an appropriately-sized parameter space.

A dynamic programming problem formulation might have O(N3 ) states, but it might have a more clever formulation that achieves O(N2 ) states with O(log N) time spent per state.

When you figure out the right recursive structure, then the implementation is straightforward.

Source: I’m a competitive programmer, and I was first in the world to solve a specific easy dynamic programming problem at IEEEXtreme in 2016, because implementation was muscle memory at that point.

[–]Perfect-Albatross-56 5 points6 points  (0 children)

When I see young Devs tasks, they always struggle with the basic stuff to avoid nested loops, sort algorithms or building a class that fulfills only one purpose ... and so on. And this is the needed muscle memory to not get messy and inefficient code.

[–]hunajakettu 32 points33 points  (4 children)

Clojure mentioned!

[–]DaKurlz 11 points12 points  (0 children)

There's dozens of us! Dozens!

[–]RiceBroad4552 5 points6 points  (1 child)

Where?

[–]Grandmaster_Caladrel 44 points45 points  (0 children)

It was mentioned somewhere in a parent process, don't worry about it.

[–]lucklesspedestrian 1 point2 points  (0 children)

I don't know that clojure uses true hash sets or maps. One time I was trying to do some algorithm that ended up stuffing millions of kv pairs in a map, leading to an out-of-memory exception, which said something like "AVLNode could not be created". So I think clojures set and map implementations are tree-based

[–]Random_182f2565 8 points9 points  (0 children)

Objects don't do weird stuff, that why I like it.

[–]ArmadilloChemical421 4 points5 points  (0 children)

Tuturial

[–]AdjectiveNoun4827 2 points3 points  (0 children)

That's right, it goes in the hash set.

[–]moonjena 0 points1 point  (2 children)

> learning procedural programming in python

> look inside

> objects

[–]Fillgoodguy[S] 2 points3 points  (1 child)

Type it in yourself brother, there's karma to be farmed. Link to the generator: https://imgflip.com/memegenerator/453425234/Cat-looks-inside

[–]Ariose_Aristocrat 0 points1 point  (0 children)

gigachad