Hacker News new | past | comments | ask | show | jobs | submit login

> Create a language to solve your problem;

> Solve your problem.

When I worked on a complex framework in a small team, we used Objective-C. In the early days of the project, we created some powerful utility methods like map and reduce which we used extensively in the early stages. These methods let us do things like traverse complex structures very compactly. Way better than the more plodding while-loop (perhaps with a stack) way of doing it. But, I found myself moving away from these later in the project in favour of more verbose code because it took me too long to understand the map/reduce code if I needed to revisit it. The longer code was, um, longer, but it was much easier to understand what I (or my colleagues) had done when I came back to this code. In my view, a bunch of very smart programmers can indeed be "hyperproductive" using a language like Smalltalk, but this hyper-productivity may not survive the longer term life of the project.




Note that map and reduce (and generally fold) tell you what happens. Loops show you how something happens, and you have to infer a higher-level concept from it yourself. That is, map belongs to a strictly more powerful language, but to benefit from it, you have to be fluent with this language.

The very same thing happened when structural programming was invented, and Fortran-iV guys were saying that all these "while" and "until" loops are harder to read than computed gotos.


This past week I sat in a class at work about the newer features of Java 8-10, mainly lambdas and streams. I was like "oh, Java is catching up I see" while another developer was like "What? I don't understand? How would you unit test a stream statement?"


Streams are reasonably testable; I wrote streams-heavy code for a year, and did not have issues with that.

Very long streams can be combined of shorter stages, and these stages are individually testable, when needed.


How is map difficult to understand? It’s the same semantics as a for loop with input and output lists, but less boilerplate.


From my personal experience, most developers that discover list comprehension etc. get excited about how much they can achieve with little code that they try to keep everything as small as possible. They end up using short, non-descriptive variable names and you need evaluate the code in your head to find out what a variable/list contains. It's even worse with non-sequential callbacks and closures.


In Python I went back and forth:

I discovered list comprehension and was exited and used them a lot. Then I went to multi level list comp. Then I realise I could never debug those so went back to loops for anything needing more than a single level. Finally I discovered Generator Expression which are basically like list comp, but lazy (not evaluated) and since then I break my code in a series of generator expression which I materialise at the end with a single list comprehension. This way I keep my code readable, it's a lot cleaner then a bunch of loops, and I also benefit of Python's special optimisation for list comprehension.


I like writing generator loops with the yield statement for more complex processing.


That’s my style as well, and I followed the same path of yours!


>It’s the same semantics as a for loop with input and output lists

Arguably it's even easier because you you generally know you won't have inter-item dependencies.


The parent did say they rolled their own map/reduce. It might not have been exactly as one would expect it to work in that case.

But yeah, map/reduce are so common nowadays that I think most people would not have a problem with them anymore. Even Java is doing them now :)

OTOH, if you've never encountered them because you come from languages that did not have them, they might be confusing at first. Some of my colleagues did have trouble getting used to map/reduce when Java8 came around.


If map() is part of the language then it's not difficult to understand because you can always read up on it in official documentation or on the web. But if the language does not support it and you create your own it is unlikely that you document it as well as the vendors of a programming language.

This may be part of the problem with hyper-productive languages in general, you get stuff done fast but it tends not to be documented as well as a publicly available programming language.

map() that is part of the language is also very STABLE whereas if you write your own you are likely to tinker with what it does here and there, what default argument-values it uses and so on.


I've written maps that I've regretted later. "map(+1, list)" isn't too bad. But as you chain things and/or put more in the lambda, it gets less comprehensible. Then, some cross cutting requirement comes in and you either need two map reduces or to just refactor to a loop.


I would say it is the difference between first-order and higher-order. While loops are first-order, thus easier to understand, while map is higher-order, thus more difficult to understand.


"Higher order" functions are about whether a function takes code as a tuneable parameter, rather than "just" (user) data.

A regular function call is first-order:

    foo(bar: Int): Int
While is usually a magical special case, but conceptually it's just a higher-order function that takes two functions:

    while(keepGoing: () => Boolean, action: () => Unit): Unit
Or, if you want to be pedantic:

    while[M: Monad](keepGoing: Monad[Boolean], action: Monad[Unit]): Monad[Unit]


Your higher-order while construct certainly mimics the normal first-order while one. But that's not really the point.


Scala's "implicit" keyword seems a famously contentious example of code obfuscating trickery




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: