7 ms·
That’s a failure of Java’s language design, not a failure of the functional/declarative paradigm. Your for loop can do all kinds of damage to the list, and you
by filoeleven 5y ago
That’s a failure of Java’s language design, not a failure of the functional/declarative paradigm.
Your for loop can do all kinds of damage to the list, and you have to read it all to find out what it does. Saner languages make the functional version more expressive.p:
return first(users.filter(u => contains(u.name, searchString))
I’m not saying JS is a sane language; it has an anemic standard library without a robust “first()” or “contains()”. But that code gets you the first user where the name matches, without resorting to indexes or null checks or worrying about how a for loop can mutate lists that it should not.
EDIT: I should have used filter(list fn) here, I was trying to write something plausible in JS instead of a purer functional language and misses that translation.
- usrbinbash 5y ago>and you have to read it all to find out what it does. Which isn't a problem, because as long as its all loops'n branches, the code is easy to understand.
- filoeleven 5y agoHard disagree. For loops do not have guarantees about in-place mutation; that’s why they require a full read. Anything that starts with a map/filter is guaranteed to only apply to the thing that it is assigned to. That’s more than worth its weight in grey hairs. EDIT: “full read” includes “everywhere else this array is used, which can have far-reaching consequences if it was passed into the containing function by reference.”
- jstimpfle 5y agoMost temporary variables are single assignment, and many newer procedural languages do have variable declaration syntax for single-assignment variables. Such as Javascript's `let`. Another wide-spread syntax feature is for-loops over collections like `for item in list`, again being extremely easy to read and not requiring any assignments. So, accidental in-place mutation is not an issue in practice. But, in-place mutation can be very useful to express logic in an easy to understand way. Coincidentally my main language does not have any of these features, and in-place mutation is like 0.1% of all my problems. (And notably, memory management is < 5% of my problems). These are all just theoretic problems, what really matters is developer experience. You can write terrible bug-ridden convoluted code in any language, ESPECIALLY with many filters and lambdas and callbacks. The issue with the functional style is that it becomes harder to see the control flow and run-time characteristics. I'm sure functional style is great to express set operations (like DB queries) but IME they tend to optimize for source code brevity and pessimize for runtime performance.
- filoeleven 5y agoDB queries are a good analogy, especially if we qualify them as atomic operations. I’m hard-pressed to find a situation where procedural mutation-in-place makes more logical sense than an atomic update of the whole list, so why not make atomic updates the default? It’s different if you’re working in lower-level code. I don’t intend to trivialize performance; the option to “go procedural” should be available. I just think it’s the wrong default. Operating systems and some kinds of Big Data need those perf boosts. But for your run-of-the-mill CRUD app, map/filter is both clearer and safer than a for loop. Strong language support encourages this both algorithmically and syntactically—unlike what Java did, which is what I originally replied to.
- int_19h 5y agoJS "let" is not single-assignment; did you mean "const"?
- jstimpfle 5y agoOops, guess you're right. I haven't written any Javascript in years.
- usrbinbash 5y ago>For loops do not have guarantees about in-place mutation; Every modern language has a `for elem in range` construct, giving exactly that guarantee, as long as the element isn't a pointer. Besides, I neither want nor need such a guarantee. There are many scenarios where in-place mutation is exactly what I want to do in a loop, and I don't want to fight the language, aka. my craftsmans tool, to do it, just because it imposes an arbitrary restriction on what I can or cannot do. Is this a potential source of bugs? Of course it is. That's why I have tests, code reviews and debuggers. And besides, nothing prevents me from doing the functional approach in languages like Golang, Python or Julia *if I want to*. I simply refuse to use languages that that force a paradigm on my code. This is true not only for "pure functional" languages, but also Java, which wants me to use OOP everywhere. To me, paradigms are tools. They need to be there when I need them, and get not get in my way when I don't.
- valenterry 5y agoThe first, filter, map, etc. functions are also only loops&branches under the hood, no? :)
- gavinray 5y agoJS has Array.some() for "contains"
- filoeleven 5y agoThe caveat there is that you cannot call it without a null check on “u.name” first. contains(null, “whatever”) would just return false instead of throwing a runtime exception. Hence my edit: users.filter() has the same problem.
- nayuki 5y agoJavaScript's "first()" is https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... .
- filoeleven 5y agoSame caveat applies here as my other sibling comment. I shouldn’t have to do null checks before calling functions.
- salawat 5y agoI shouldn't have to QA properly written code. Alas, reality, she is a cruel mistress.
- deleted 5y ago[deleted]
- FpUser 5y ago>"Your for loop can do all kinds of damage ..." So can programming in general
- deleted 5y ago[deleted]