I was afraid this would be some sort of contorted framework to let you use C++ to write Lisp. Glad I was wrong. Carmack is spot-on here:
"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.
To me, "easier to hold in your head" is "easier to reason about". I can also imagine someone describing functional style (the thing Carmack says makes state presented to your code explicit) as "more mathematical".
One of his comments kind of stuck out when I read it.
... 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.
This is probably the best summary of functional programming, written by the best "pragmatical" programmer of the world. I wonder how much Haskell code Carmack must have written to reach this kind of knowledge... and whether it is open source. It would be a good read for the weekends.
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.
Not entirely nonsense—immutability is helpful even in the absence of referential transparency—but still, a “pure” keyword would be great. Now, what I’d really like is for the type system to be flipped on its head with respect to immutability: make “const” the default and explicitly qualify mutable types with “mutable”. A guy can dream…
GCC has a 'pure' attribute. I don't know if it's only used for optimization, but it also serves as a kind of comment for whoever looks at the function in the future.
"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.
For anyone wondering about adapting real world
problems to FP style, here's an article about someone
reimplementing pacman in FP: http://prog21.dadgum.com/23.html
"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 disagree. Of course not _everybody_ can abandon C++ but some really can. I have developed C and C++ software for many years but with Racket Scheme (a functional language) I am MUCH more productive now. This works because I think and code functionally which is a totally different approach to the way how coding in C++ is done.
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++.
Great article, I love the way Carmack communicates.
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.
This headline isn't very descriptive; more useful might be "John Carmack discusses the practical benefits (and limitations) of a functional programming style."
I like this a lot because it summarizes the direction my own C++ has taken since I first learned about FP. I've found that making a member method functional (i.e. changing usage of member variables into passed parameters where reasonable - I never use globals) makes it more reusable from an OO point of view. The biggest gains by far have been in multithreaded programming.
[+] [-] kibwen|14 years ago|reply
"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.
[+] [-] dons|14 years ago|reply
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.
[+] [-] bithive123|14 years ago|reply
[+] [-] nuje|14 years ago|reply
[+] [-] pjmlp|14 years ago|reply
One just has to take care to minimize mutability, as Carmack wrote on his blog entry.
[+] [-] cobrausn|14 years ago|reply
... 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.
[+] [-] lolcraft|14 years ago|reply
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.
[+] [-] evincarofautumn|14 years ago|reply
[+] [-] el_presidente|14 years ago|reply
[+] [-] heretohelp|14 years ago|reply
[+] [-] vilya|14 years ago|reply
"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.
[+] [-] InclinedPlane|14 years ago|reply
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.
[+] [-] im3w1l|14 years ago|reply
[+] [-] fulafel|14 years ago|reply
[+] [-] tomrod|14 years ago|reply
"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."
[+] [-] bitcracker|14 years ago|reply
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++.
[+] [-] pestaa|14 years ago|reply
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.
[+] [-] sausagefeet|14 years ago|reply
[+] [-] grout|14 years ago|reply
[+] [-] agumonkey|14 years ago|reply
http://lambda-the-ultimate.org/node/1277
[+] [-] Tossrock|14 years ago|reply
[+] [-] rvkennedy|14 years ago|reply