FunctionalPlus – helps you write concise and readable C++ code
github.com
github.com
See https://github.com/facebook/folly/blob/master/folly/gen/test... for an example.
Code: https://github.com/Ableton/atria/tree/master/src/atria/xform...
CppCon 2015 session: http://sinusoid.es/talks/transducers-cppcon15/ https://www.youtube.com/watch?v=vohGJjGxtJQ
If you want to compile C++ (or C) really fast, look at icecc: https://github.com/icecc/icecream
One sentence that comes to mind is "If you write C++ like you write Java, you are unlikely to see any benefit."
It's more strategic to teach people to write readable code (exactly like the OP does), and then ... to teach them how to use a profiler.
I love profilers as much as the next person, but if you build a system from inefficient building blocks, you may eventually need to build it again. But in a professional setting you are likely to be told not to do build it a second time, or you will be gone before that time comes, leaving someone else to clean up your moribund codebase of a thousand inefficiencies.
I hear a lot of people complain about higher levels of abstraction in languages like C and C++, because they take away control or don't allow them to squeeze every last drop of performance out of their programs.
I also see a lot of software in the wild that was programmed in C and C++ and runs very fast... but is buggy as hell or has pretty nasty security bugs.
The fact is that, regardless how good you think you are, most likely you're not one of the few people who can write fast, bug-free[0] software in C and C++. I certainly am not despite having written quite a bit of C and C++ in the over the years. The amount of high-impact bugs (especially security bugs, eg Heartbleed)
[0] Where I really mean: no severe bugs (data corruption, data loss, security flaws)
As an application developer its a big pain to realize that the library that you have built your application around now needs to be incised out for performance reasons. In theory, if you design your interface well one can switch out libraries, but it is rarely as clean as what theory claims. Interfaces set, if not in stone, at least in in loose concrete, the data-structures that are convenient to use.
EDIT: I hasten to add that I am not complaining about the library, far from it.
> it makes sense to make the library lean and lacking obvious bloats, or at least make efficient code paths possible without forcing the application programmer to indulge in excessive verbosity.
Does not apply to these people:
> It's hard enough teaching people to avoid inefficiency when it's right there in front of them, and harder still when you encapsulate inefficiency in a pretty package.
who, by definition, are not experienced enough to write code that is sufficiently lean and lacking obvious bloat, or at least make efficient code paths possible. If they were, then they won't have a problem with the pretty package either.
I only wanted to point out that in the context of the comment you replied to, I didn't feel that those were the people who should be worrying about optimised code.
Compare:
for (int x : numbers) {
if (1 == (x % 2)) {
odds.push_back(x);
}
}
auto odds = KeepIf(IsOdd, numbers);
To me, the first case is preferable. The 2nd case uses custom functions that may not be familiar to the maintainer, and semantics are clearly hidden (e.g. does KeepIf() modify the list, return a copy, or return some kind of intelligent generator object that still depends on the lifetime of "numbers"?).Suppose I discover that my application starts crashing with the odd number 15 and I have to work around that case very quickly. The loop version above is trivial to modify, whereas I have no idea how the 2nd version would be modified to filter out one value! And if I want to do several things with the numbers while they're being found (e.g. print them out), the loop is easy to change but the 2nd version basically has to be replaced entirely (and replacing even a concise expression is risky due to the issues above, e.g. unclear semantics).
Now compare approaches for another case:
if (FindWord("I", team)) ...
if (Contains("I", SplitWords(team))) ...
This shows a general problem with a "functional style" at times: it's placing constraints on the implementation that don't need to be there.To me, the first style is preferable because FindWord() could easily walk a raw string and stop as soon as it finds the target word, with a chance for better-than-N average complexity. The second case would mandate: copying strings, visiting all characters in the string every time, and revisiting at least some of the characters in the form of words.
Finally, I think that the C++ standard algorithms, lambdas, and compact-"for" do allow a lot of these tricks to be avoided. Consider algorithms like std::all_of() for instance, which can be combined with lambdas to produce the same results as examples like "AllBy(And(..." but without the downsides I mention at the beginning of my comment.
if (Contains("I", SplitWords(team)))
so I added it to the README.If you don't want the 15 in the odds, just to this:
auto goodOdds = without(15, keep_if(is_odd, numbers));
The fact, that `keep_if` does return a copy can easily obtained by looking at the function signature or the type of `odds`. Both things should not be complicated with a modern IDE.I agree with you in general. The library is not made for performance-critical stuff.
But the "raw loops etc. are easier to understand by outsiders" seems like an argument agains using any libraries at all.
It's a trade-off.
This is not a problem with "functional style", it's a problem with library design.
writing
map (+2) (map (+1) (map (+3) xs))
will be just a single pass over a list in Haskell, with 3 function applications (maybe 1 if that is optimized to (+6)).I know it is not designed perfectly.
You might want to have a look to std.algorithm from Phobos (the D programming language standard library) ; it's full of such utilities : http://dlang.org/phobos/std_algorithm.html
That's a shame there's nothing similar in the C++ standard library.
In one case I used a python wrapper around a C++ core, but when it came time to re-write it we switched to pure python and have so far hit our performance benchmarks - mostly because libraries like OpenCV or PyCuda are now able to efficiently wrap our critical paths.