Functional Programming in C++
altdevblogaday.com
altdevblogaday.com
"My pragmatic summary: A large fraction of the flaws in software development are due to programmers not fully understanding all the possible states their code may execute in. In a multithreaded environment, the lack of understanding and the resulting problems are greatly amplified, almost to the point of panic if you are paying attention. Programming in a functional style makes the state presented to your code explicit, which makes it much easier to reason about, and, in a completely pure system, makes thread race conditions impossible."
Too often I've seen functional proponents, when asked why we ought to use functional languages, rely on facile arguments such as "it makes your code more concise, therefore easier to hold in your head" or "it makes your code more mathematical, and therefore easier to reason about". Like Rich Hickey, Carmack gets it right.
Essentially, a bad argument for functional programming says, "here is what functional programming does well; here is why that helps you". A good argument for functional programming says, "here is a very real problem that you have encountered; here is the remarkably effective way in which functional programming addresses it". Note the inversion, especially the focus on solving problems rather than on justifying paradigms.
If the states are fewer, the code is simpler. I can only hold simple things in my head :)
I think everyone's basically saying the same thing.
I gave a talk on how FP approaches force you to minimize accidental complexity recently, capturing this view, http://code.haskell.org/~dons/talks/padl-keynote-2012-01-24....
I go into this more explicitly in http://www.jerf.org/iri/post/2908 .
I think s/h/it is the correct pronoun to use to cover all those cases.
(yes, it's /s. When I see "she" used to imply the author is oh, so progressive and non-sexist, I resort to sarcasm).
>> The minimization is done by the programmer because
>> she is lazy and longs for conciseness.
I view longing for conciseness to be the sign of a good programmer, not a lazy one.http://www.folklore.org/StoryView.py?project=Macintosh&s... "He thought his goal was to write as small and fast a program as possible, and that the lines of code metric only encouraged writing sloppy, bloated, broken code.'
http://c2.com/cgi/wiki?LinesOfCode "Measuring software productivity by lines of code is like measuring progress on an airplane by how much it weighs."- Bill Gates
One just has to take care to minimize mutability, as Carmack wrote on his blog entry.
... but many object[s] are large enough to constitute a sort of global state all their own, blunting some of the clarity benefits of pure functions.
I think we've all run into (and probably coded) our fair share of objects that were basically this - there is only one of them, and it has a lot of state associated with it. I never thought of it before as basically just encapsulating global state into an object. It almost seems... unavoidable, or at least really hard to avoid.
Also this was hilarious.
As an extreme example, you can write a pure DrawTriangle() function that takes a framebuffer as a parameter and returns a completely new framebuffer with the triangle drawn into it as a result. Don’t do that.
BTW, I think the pure keyword in C++ would be great. I wrote some C++ in school, and even I can tell that const, as applied to functions, could use some retirement. It's nonsense to keep this unmodified, stateless so to speak, but allow global variable assignation, and so on.
I would never use those attributes except - maybe - in the most critical loops and then only with a big "WARNING!!!" sign. Why? GCC does not / cannot enforce the guarantees given by "const" and "pure" yet the optimizer always assumes they are true. I.e. accidentally reduce the purity of a function decorated in this way.. and you might create very hard to find bugs.
This is a general problem in C and C++, those languages simply weren't designed to enforce such contracts. C99's "restrict" has the same problem.
This is, of course, in addition to its other meanings in the language.
"Most developers are not very good at predicting the future time integrated suffering their changes will result in."
So given a graph with time on the x axis and maintenance effort on the y axis, the area under the curve is the amount of suffering caused. That's a pretty good take-away.
Acute damage gains much more attention than diffuse damage. Thus you have a common problem of developers taking "shortcuts" and accruing huge amounts of long-term technical debt in exchange for temporary short-term advantages, and you have the equally common problem of internal tooling that just barely gets the job done but also introduces massive amounts of waste of time and effort across the entire institution.
"I do believe that there is real value in pursuing functional programming, but it would be irresponsible to exhort everyone to abandon their C++ compilers and start coding in Lisp, Haskell, or, to be blunt, any other fringe language. To the eternal chagrin of language designers, there are plenty of externalities that can overwhelm the benefits of a language, and game development has more than most fields."
I doubt that functional programming in C++ will be as elegant and effective as in a real functional language where everything is functional. The approach of C++ seems to be and to support "everything". But will that support more maintainable code? I don't think so. Quo vadis, C++?
Btw Implementations like LuaJIT demonstrate that virtual machines have become amazingly fast. So, even for performance you don't need to be stuck to C++.
Can someone please explain how much of these performance worries is mitigated by C++11 move semantics? To me it seems like the functional style is becoming a possibility when one doesn't have to worry about the penalty of copy operations.