Hacker News new | ask | show | jobs
by overpaidgoogler 3990 days ago
One difficulty with functional style c++ is just how verbose it is. Every time I tried to use std::transform (the equivalent of "map") I had to delete it and rewrite as a loop because it was just too hard to read. Functional style on a large scale is still possible.
3 comments

It really irks me that the std algorithms library seems to have been designed without any consideration for usability given how much I would love to rely heavily on the generic algorithms it contains. For example consider the simple task of testing to see if an element exists in a container:

    if (std::find(container.begin(), container.end(), element) != container.end())
My fingers are now cramping and my eyes are crossing trying to read that. It beggars belief that overloads don't exist which take an entire range which is all I want to do 99% of the time.
Well the containers that have fast lookup (set, map and their unordered_ and multi_ counterparts), all have efficient .find() member functions. The general philosophy of the idealised STL is not to provide you with anything you can compose efficiently yourself.

A 3-4 line template will will give you a terse boolean contains() method, but it won't give you any big-O guarantees, and having such a thing would encourage very inefficient patterns (like calling contains() and then doing a find() if it's true, which effectively does the lookup twice). Why introduce a weak abstraction? If you're forced to write it yourself you're more likely to understand the implications.

Alex Stepanov, who wrote the original STL, is very much a believer in fundamental indivisible building blocks like iterators and algorithms and careful API design. To grok more about why things are the way they are, I recommend watching his "Efficient Programming with Components" lectures[0]. Over the course he builds up, in excruciating detail, an implementation of merge sort, reasoning about, and discussing with his students, the implications of almost every line of code.

And yes, Stepanov complains about the lack of terseness and expressiveness in C++ as well.

[0] https://www.youtube.com/playlist?list=PLHxtyCq_WDLXryyw91lah...

There is a legitimate complaint with that specific example, though: having to write .begin() and .end() is obnoxious instead of using more modern iterators/ranges.
well the slightly more concise way of writing it is this:

    auto e = end(container);
    if (e == std::find(begin(container), e, element)) { ... }
...but yeah, it sucks. If I were doing this though, i'd to be encapsulating things in to a higher level abstraction. Seeing std::find in more than 1 place in a file is a red light for me.
Holy cow, thank you so much for the lectures!
Much the those issues are addressed in various boost libraries. There is one which wraps all the algorithms and containers in range classes so that all the f(c.begin(), c.end(), g) silliness gets replaced with f(c, g). There is another one which makes it easy to create streams of transforming and mapping functions with a F1 -> F2 -> F3 interface.
The article is not about the functional C++ you mention. It is about using pure functions (functions that do not modify global context).
I get that. But the two ideas are very closely related. See also my final sentence.
I'm really hopeful that Concepts will dramatically reduce the amount of code needed for std::transform. Imagine no begin() or end(). It would suddenly become less verbose than the classic for loop.
That problem is due to the STL not being built around iterators/ranges. I don't see how concepts enter into it (though contra Andrei Alexandrescu, I'm still a big believer in concepts).