5 ms·
Replacing the for loop with its functional equivalents would make it less readable. Readability is in the eye of the beholder. A tidy functional equivalent mig
by Chris_Newton 12y ago
Replacing the for loop with its functional equivalents would make it less readable.
Readability is in the eye of the beholder. A tidy functional equivalent might look something like this (in a made-up syntax with typical functional idioms):
getIncompleteTaskSummaries membername =
fetchData
>>> tasks
>>> filter (task => username task == membername and not complete task)
>>> map (subsetkeys ["id", "dueDate", "title", "priority"])
>>> sortwithkeyfn getTime
Compare that with the explicit loops and tests above:
var getIncompleteTaskSummaries = function(membername) {
return fetchData().then(function(data) {
var incompleteTasks = [];
for (i = 0; i < data.tasks.length; ++i) {
var task = data.tasks[i];
if (task.username == membername && !task.complete) {
incompleteTasks.push({id: task.id, dueDate: task.dueDate, title: task.title, priority: task.priority});
}
}
incompleteTasks.sort(function(a, b) {
return a.getTime() - b.getTime();
});
return incompleteTasks;
});
}
In practice, functions like filter, map, subsetkeys and sortwithkeyfn would probably be in your standard library and immediately familiar to anyone used to programming in such a language, so the only interesting details are the interesting details: which tasks you want to pick out, how you want to summarise them, and how you want the results ordered. Depending on what else is going on, you might even extract some or all of those three details into named one-liner functions to make the main algorithm more self-documenting and/or to allow those concepts to be reused elsewhere.
The functional version as shown reduces 10 substantial lines with a lot of temporary variables and deep nesting to 6 total lines that each have a clear, self-contained purpose and that collectively systematically transform your input to your output. To my eyes, that style is far more readable and maintainable than manually reinventing fundamental algorithms like filter and map and camouflaging the interesting details within three or four levels of context.
Edited to add: Often the thing that makes functional style awkward is when a language that wasn’t designed with that style in mind adopts some of the useful concepts but without the elegant syntax and idioms to match. For example, we have somewhat unwieldy notation for defining quick local functions in JavaScript, lambdas that work as long as you can do everything on one line in Python, and the horrific lambda expression notation in modern C++. But I don’t think it’s helpful to conflate this with functional programming style itself, any more than it’s helpful to conflate Java’s verbosity with static type systems.
- skybrian 12y agoWell, I could convert it to a SQL statement too, but then we're no longer using a general-purpose language. Filter, map, and so on are additions to the basic for loop that everyone already needs to know how to use. "you might even extract some or all of those three details into named one-liner functions" No. Replacing familiar operations with unfamiliar ones (adding a level of indirection) doesn't add readability or make it "more self-documenting" than pure boilerplate code that everyone's seen many times before and will see again. But these sort of arguments never reach a conclusion. The way to test it would be to teach beginners and see which one is easier to teach. That's a bit beyond a casual internet discussion, though. :-)
- qu4z-2 12y agoI see this assumption quite frequently -- That what is easy for a beginner is easy for an expert. I'm not sure that's the case. FWIW, I'm in the anti-boilerplate camp.
- skybrian 12y agoWell, most things are easier for an expert, or they wouldn't be an expert, right? I think it's good practice to try to write code that's readable by people with a wide variety of skill levels.
- rnbwd 12y agoI began programming in September of last year. For loops were trivially easy to understand (took me about a day), 1-2 weeks to become proficient. I started with php, moved to 'jquery', and then rails. Rails pisses me off. I said fuck this class I'm learning node/javascriot. After a week of js I switched to clojure (my instructor hadn't even heard of it, this is a full day bootcamp coding course). Rich Hickey is my single greatest influence in programming habits styles. I spent a few months, off and on, learning clojure. I still can't program competently, but I learned how to replace for loops with map / filter / reduce. Once I realized what was going on there, I had my greatest 'ah ha' moment in programming thus far. Clojure blogs led me to Om, om to react, react to frp and gulp, gulp lead to streams / piping, and I haven't used a for loop in 6 months. It's boilerplate that's so trivial, you only need to code for about 3 months for the functional abstractions to become more useful to you. It took me a few weeks to learn how map, filter, reduce work. It took me a few hours to learn a 4 loop. I still consider myself am amateur programmer, but this trend of code abstraction will continue rapidly, and our CPUs and more that capable of handling the potential performance hits.