6 ms·
I really want to like functional programming, but the functional version of each of these seems less readable and more verbose.
by obstinate 12y ago
I really want to like functional programming, but the functional version of each of these seems less readable and more verbose.
- CmonDev 12y agoI guess this is why Microsoft diverged from the "standard" names like 'map', 'collect' and 'filter' in favour of more human-oriented SQL-like LINQ: 'select', 'where', 'toList'. I have to read the underscore.js documentation every time I am using it :(.
- api 12y agoMS did the right thing. A huge barrier to FP adoption is the unnecessarily obtuse terminology. In playing around with FP languages I often find myself having to re-look-up basic syntax because the terms are simply so obtuse that they won't "stick" in my head. I think it comes from FP's rooting in mathematics, and math is itself unnecessarily arcane.
- sswezey 12y agoI disagree. The benefit of having the standard terms is they are the same in every FP library you use. If you spend the time to learn and internalize them within one, it'll be the same in every language or library that implements them. I don't understand how map, filter, collect, reduce are obtuse or arcane.
- api 12y agoThose aren't the worst offenders. I'm referring to curry, cadr, lambda, monad, etc. But map is confusing: it's also a data structure. "Wait, does map() create a new key-value dictionary?" Filter and collect are okay. Reduce is pretty arcane but tolerable, but the actual operation feels intuitively closer to "categorize" or "group." My point about math was cultural. Math seems to revel in having its own peculiar and often even domain specific (even within mathematics!) terms and symbols for things.
- rosta 12y agoreduce (or fold) would be accumulate, certainly not categorize or group.
- Someone 12y ago1. Map isn't "also a data structure", the data structure is a way to implement a mapping function. There is no conceptual difference between code and data (for an example, see http://en.m.wikipedia.org/wiki/Cons#Not_technically_fundamental http://en.m.wikipedia.org/wiki/Cons#Not_technically_fundamen...) 2. cadr is relatively easy, if you know your assembly (http://en.m.wikipedia.org/wiki/Car_and_cdr#Etymology http://en.m.wikipedia.org/wiki/Car_and_cdr#Etymology) :-) And math has locally defined terms because one cannot give every concept a unique short meaningful memorable name. That is no different in computer science, where 'integer' can include negative numbers or not, may or may not wrap around, can be any number of bits or potentially unlimited, may include minus zero, etc.
- luddypants 12y ago>> 2. cadr is relatively easy, if you know your assembly (http://en.m.wikipedia.org/wiki/Car_and_cdr#Etymology http://en.m.wikipedia.org/wiki/Car_and_cdr#Etymology) :-) If you know IBM 704 assembly...
- kasey_junk 12y agoInteresting enough, my academic background was mostly FP based, but my first heavy industry use of the terms was with the LINQ libraries. I have since had lots of experience with the more academic terms and can pretty easily translate back/forth with no problem. Except for filter. I routinely forget if it is "filter in" vs "filter out". It is easy enough to look up, but I never had that problem with LINQ's "where".
- KfZ 12y agoI'm not sure how those are supposed to be more human-oriented? I'll grant you "where" might be a slight improvement over "filter", but calling "map" "select"? I can't make sense of that even knowing what it's supposed to mean. If anything I'd assume it to be yet another synonym for filter.
- remon 12y agoThis was exactly what I was thinking when I read the code. The goal should not be to remove loops. As a language construct there is nothing wrong with loops itself. The goal should be to make more readable and maintainable code, preferably without increasing verbosity. The functional alternatives posted here are not actually code quality improvements and should not be presented as such.
- BFay 12y agoI welcome the functional features, but I have to agree that these specific examples are ugly compared to the more familiar alternatives. Maybe this will look more readable after getting used to it, but I'd much rather be looking at Clojure or Scala for now.
- bollockitis 12y agoOut of curiosity, could you share an example of how this compares to Clojure or Scala? I am not familiar with either.
- markc 12y agoHere's a quick version in Clojure. I'm sure it can be done cleaner than this.. (def articles [{:title "title1" :author "author1" :tags #{:Java :t2 :t3}} {:title "title2" :author "author1" :tags #{:Jvxa :t2 :t3}} {:title "title3" :author "author3" :tags #{:Java :t3}}]) ;; find the first article in the collection that has the tag “Java”. (first (filter #(contains? (:tags %) :Java) articles)) ;; ==> {:tags #{:t2 :Java :t3}, :title "title1", :author "author1"} ;;get all the elements that match instead of just the first (filter #(contains? (:tags %) :Java) articles) ;; ==> ({:tags #{:t2 :Java :t3}, :title "title1", :author "author1"} {:tags #{:Java :t3}, :title "title3", :author "author3"}) ;;group all the articles based on the author. (group-by :author articles) ;; cheating? ;; ==> {"author1" [{:tags #{:t2 :Java :t3}, :title "title1", :author "author1"} {:tags #{:Jvxa :t2 :t3}, :title "title2", :author "author1"}], "author3" [{:tags #{:Java :t3}, :title "title3", :author "author3"}]} ;;find all the different tags used in the collections (apply clojure.set/union (map :tags articles)) ;; ==> #{:Jvxa :t2 :Java :t3}
- mattnewton 12y agoI think the examples shown here don't really show how it can help- the real win for me is if you already have a function to filter over (like "article.isJava()" or something) it becomes much clearer. It also is eye opening to see or higher order functions like pluck or flatmap that build off these blocks. Edit- there is a good flatmap example there that I glossed over when first reading. It looks like Java even has serviceable syntax for passing around lambadas like that now too, that is cool.
- jimktrains2 12y agoI disagree. Perhaps I'm simply more use to seeing this style, but I feel it's more concise, more maintainable, and more easily built on than the loop-based version. Additionally, I find it to be more semantically clear as to what the expected behavior is, as opposed to reasoning about the loop, especially when filters become complex.
- TYPE_FASTER 12y agoI don't think the article should have framed it as "let's replace traditional looping constructs," but "let's apply a filter or query to a data set." That's how I've typically seen .NET LINQ written up, and it makes more sense to me.
- hibikir 12y agoThe extra verbosity comes from the way java 8 is trying to make functional programming more comfortable while doing as little as possible to the language to do it. When you add all the sugar to make lines more expressive, then you'd hear complaints like the ones Scala gets about having too many ways of doing the same thing. in scala, finding the first article looks like: def topJavaArticle(articles:List[Article]) = articles.find(_.tags.contains("Java")) which returns an Option[Article], so it handles the null check. Since List in scala already handles functional constructs directly, then the filter example is just as easy: def javaArticles(articles:List[Article]) = articles.filter(_.tags.contains("Java")) group by author? def byAuthor(articles:List[Article) = articles.groupBy(_.author) And yes, that's the entire method definition, signature included. We could have added the return types for documentation if we felt like it. You might still not like the style, but you can't say it's more verbose than the floor loop. Backwards compatibility and design philosophy makes sure that Java 8 doesn't go hard enough on the sugar. It's why I am not optimistic of Java's future. There's awesome features out there in newer languages, like proper pattern matching, that Java just won't be able to borrow from functional languages.
- thescrewdriver 12y agoIt's doesn't take long when working with functional code to never want to go back to loops.
- Figs 12y agoI had the opposite reaction after having to work with a number of complicated reductions; in a lot of cases, a short for-loop and accumulator variable would have made the code much easier to read...
- breckinloggins 12y agoI saw a quote recently from Rich Hickey: "Elegance and familiarity are orthogonal." I didn't fully understand this concept until I read your post and found myself disagreeing with you, thinking "what is obstinate talking about? OBVIOUSLY the streams way is way more readable and far less verbose". The thing is, I can't believe I'm thinking that because I was exactly in your place a few months ago. Since that time, however, I've become very familiar with functional styles and now the Java 8 streams way seems "almost, but not quite right" and the imperative iteration style seems "gratuitously complicated and philosophically wrong... I mean... look at all that special syntax! That mutation! The horror!" All of this is to say that I'm not quite sure either of us is more correct than the other, but familiarity does seem to cause a profound mental shift.
- obstinate 12y agoIt might be worth mentioning that I already am quite fimiliar with functional concepts and occasionally use them in my code. I find them more verbose in C++ and Java despite my familiarity with them.
- codygman 12y agoWhat about this Haskell example doing the same tasks? https://news.ycombinator.com/item?id=8878421 https://news.ycombinator.com/item?id=8878421