
Functional programming in C++ (2012) - tosh
http://www.gamasutra.com/view/news/169296/Indepth_Functional_programming_in_C.php
======
W-Stool
This guy helped invent the FPS genre and all the technology it took to make
it, back in the MSDOS days - which is pretty incredible if you knew what he
had to work with in terms of CPU and memory back in those days. Like Dave
Cutler, never a guy to toot his own horn much either. Well done John, thank
you for all your contributions to the tech and the craft.

~~~
the_af
> This guy helped invent the FPS genre

I find it curious, but perhaps inevitable, that someone like John Carmack
requires this introduction. If you played videogames in the 90s / early 00s or
were at all interested in 3D programming, it was impossible not to have heard
of him. He was (is?) probably one of the cleverest programmers of his time.

This article of his gets reposted time and time again to HN, which makes sense
because it's very interesting. This is the first time I've noticed people not
knowing who the author was.

I wonder if a few decades from now, tech-minded people will wonder who Linus
Torvalds, Brian Kernighan or Dennis Ritchie were. I suppose they will!

~~~
mcnichol
I don't think it's uncommon for people to learn from the top down and after
some time and a bit if passion find themselves digging into the roots of it.

It came across as a tad condescending although I can easily believe it wasn't
meant that way and you are just open mindedly sharing perspective as is the
point of all this.

I reply not to just make that comment but actually to recommend a book (that
many may have possibly already read) which gives a rich history well worth it.

[https://www.amazon.com/Hackers-Computer-Revolution-Steven-
Le...](https://www.amazon.com/Hackers-Computer-Revolution-Steven-
Levy/dp/1449388396)

They dive into East and West coast history as well as the influences of gaming
which I think ties to this threads closest.

Its long, engaging, and the audiobook is just a kick.

If you are on that cusp of wanting to learn a bit more of where we come from
with an Americana feel, they have done a fantastic job here.

------
FPGAhacker
Quote > The factors that allow programs in functional languages to sometimes
be more concise than imperative implementations are pretty much orthogonal to
the use of pure functions — garbage collection, powerful built-in types,
pattern matching, list comprehensions, function composition, various bits of
syntactic sugar, etc. For the most part, these size reducers don't have much
to do with being functional, and can also be found in some imperative
languages.

—

Amen. I think people new to functional programming are thrown by this, and I
think some long time adherents of functional programming have adopted these
“factors” as part of the definition.

Definitions change, that’s fine, but the confusion of ideas isn’t good.

Anyway, are there functional data structures widely available to c++? I assume
there are. Without them, functional programming has a heavy cost.

Clojure, for one, would not be very attractive without having adopted
Bagwell’s data structure concepts.

~~~
fro0116
The challenge then, as with essentially every language that doesn't use
persistent data structures _as the default_, is having to recursively convert
to and from those persistent data structures at the edges of your system where
you need to interact with third party libraries that likely won't be
consuming/producing those data structures natively.

Unfortunately this is where the value proposition of a non-standard data
structure library usually breaks down for general usage. That recursive
translation layer sitting at the edge of your system is generally enough to
completely blow up your performance budget and many times leave you worse off
than if you had just used the default mutable data structures and made naive
shallow copies everywhere in the first place.

The best case study for this is JavaScript, which by now has a fairly
substantial following of functional programmers, and has an excellent
persistent data structures library in ImmutableJS, but the vast majority of
functional codebases in JS just end up doing shallow-copy-on-write using the
default mutable data structures regardless, because of the difficulty of
taking proper advantage of the performance benefits of persistent data
structures in an ecosystem that overwhelmingly deals in mutable data
structures. That said, the fact that C++ is not a garbage collected language
and the associated developer ergonomics costs of having to manually clean up
your own shallow copies might skew the value proposition a bit, but given that
if you're writing in C++ you're probably in it for the raw performance in the
first place, it's unlikely to be enough to tip the scales.

------
pmarreck
The key points he makes:

"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.

"No matter what language you work in, programming in a functional style
provides benefits. You should do it whenever it is convenient, and you should
think hard about the decision when it isn't convenient."

------
lsh
Excellent read, I still remember a lot of it. There is also the accompanying
Quakecon presentation where John Carmack talks at length about all this:
[https://www.youtube.com/watch?v=1PhArSujR_A](https://www.youtube.com/watch?v=1PhArSujR_A)

------
oever
Ivan Čukić wrote a book about this last year.

[https://www.manning.com/books/functional-programming-in-c-
pl...](https://www.manning.com/books/functional-programming-in-c-plus-plus)

The book is well written and it has useful techniques for if you want to do
mostly functional programming and want to stick to C++.

------
mattsfrey
Wow, I never saw this. I independently migrated to functional programming once
exposed many years back and definitely couldn't imagine doing software any
other way at this point, awesome to see my childhood hero endorse it though
none the less.

------
dadrian
I saw this when it was originally written back in 2012. This article is
amazing, and had a larger impact on me than anything else I've ever read about
software engineering.

------
waynecochran
One tiny baby step towards functional programming in C++ is to avoid
assignment statements as much as possible and instead use const
initialization:

    
    
         const type foo = value;
    

Assignment statements mutate state, whereas 'foo' above is an alias or cached
value which can not mutate state. This is much like the ‘let’ keyword in Lisp
or Swift. It is much easier for both the programmer and the compiler to reason
about non-mutating expressions. Many compiler suites (e.g., LLVM) use static
single assignment (SSA) for their intermediate form which opens the door for a
lot of optimization. Anyway, it is a small thing and can act as a "canary in
the mine" if you find you can not refactor your code into this form.

~~~
pmarreck
There are some corner-cases where immutable data still fails
algorithmically... for example I do not know of a performant quicksort that is
written in an immutable language (but please, someone correct me if I'm
wrong!). It's so wrong, too, because the code for functional quicksort is so
beautiful... here it is in Haskell

    
    
        quicksort [] = []
        quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater)
            where (lesser, greater) = partition (< p) xs
    

and here it is in Elixir

    
    
        defmodule QuickSort do
          def qsort([]), do: []
          def qsort([pivot | rest]) do
            { left, right } = Enum.partition(rest, fn(x) -> x < pivot end)
            qsort(left) ++ [pivot] ++ qsort(right)
          end
        end

~~~
Tarean
You can write the imperative quicksort in haskell and wrap the mutation so it
can't escape.

This forces you to copy of the incoming array but optimizations can remove
intermediate copies. This is similar to r-values in c++, for instance

    
    
        quicksort (fromList [10, 9..1])
    

would only do one allocation with optimizations.

    
    
        freeze . quicksortMutable . copy . new . New.unstream $ Bundle.fromList [10,9..1]
        new . modify quicksortMutable . New.unstream $ Bundle.enumFromStepN 10 (-1) 10
    

Also, what you posted is tree sort not quick sort.

~~~
pmarreck
Isn't quicksort a type of tree sort? (having just googled both, but not
finding said statement)

------
usgroup
Out of interest:

Has anyone made anything non-trivial in an FP style in C++ ?

If so, what frameworks did you use? What would you recommend?

Have you tried easyLambda, or used it in production?

Also, is a dynamic data structure library you'd recommend for C++? Something
that makes on the fly maps and things like that easy to implement?

------
rurban
He advises to use more copy by value, fine, but C++ is not the right language
to do that. It is even by far the worst language to that.

Better functional languages do have the optimizations needed to work in such a
style, such as a generational GC, safe stack allocation, an optimizing
compiler (for that problem, not C++ problems) and a proper type system. Good
functional languages outperform C++ with OpenMP in performance, readability,
maintainability and safety. And they explicitly disallow all the problems
which do come with C++.

------
charlysl
I am by no means an expert, but I find this article to be very superficial,
and not very useful for people new to this in terms of learning the core
concepts. For instance there is no mention of the Interpreter, Visitor and
Composite GoF design patterns, which are crucial to doing functional
programming in OO languages. If you are curious about this, it is very well
explained in some of the lectures (10, 11, 13, 14, 15) of the OCW MIT course
"Elements of Software Construction" 2008 version [1].

For a much more in depth and accurate discussion of the trade offs between
functional and OO programming, I recommend the book "Concepts, Techniques,
Models of Computer Programming". For instance, this book explains the
technique of Impedance Matching to deal with programs where different
components have different degrees of what the article's author (very losely)
calls "purity".

[1] [https://ocw.mit.edu/courses/electrical-engineering-and-
compu...](https://ocw.mit.edu/courses/electrical-engineering-and-computer-
science/6-005-elements-of-software-construction-fall-2008/lecture-notes/)

~~~
jpz
DoF design patterns is Java bollocks IMO.

It's only Java developers and to a lesser extent C# developers that really go
nuts for this stuff. Visitor is clearly a framework for expressing
multimethods - thus one can say Visitor is merely a workaround for the
constriction of expressiveness of a given language - which is a claim made
about many of the GoF patterns.

Singletons as a pattern? How is that different to global variables? It isn't.

~~~
charlysl
Design patterns are just a convention; I would be as uncomfortable overusing
them as jumping on the current pattern bashing fad.

The Interpreter pattern is just a technique for doing what amounts to pattern
matching but in an OO language, the Visitor is its dual, and Composite is
handy to represent arbitrary arity trees.

They allow you to represent algebraic types in an OO language, and I guess
that they are design patterns because they can be applied systematically in
any domain without having to reinvent the wheel, given that designing with
them is driven by the information's structure only, just like in regular FP
languages.

Abusing them is just as bad as abusing any other design technique, but when
applied correctly they greatly improve program structure and maintainability.

Visitors have nothing to do with multimethods. Their purpose, in this context,
is to improve maintainability when in a given functional program written in an
OO language you would be more likely to add new functions rather than data
type variants; Interpreter would be preferable when the opposite is the case.

Do you know of better ways of systematically doing FP design in C++? The
article doesn't mention any.

~~~
nurettin
The article isn't about design patterns, it is about using the new functional
programming primitives which C++ relatively recently acquired through the
standardization process.

Suggesting to use a syntax for lambda or currying or transferring closure
parameters or making copies of data in order to avoid thread problems is not
remotely within the same category as "visitor pattern".

~~~
charlysl
> it is about using the new functional programming primitives which C++
> relatively recently acquired through the standardization process.

Sorry, I couldn't find any mention of such new primitives in the article.
Which are they?

~~~
nurettin
I understand `constexprs`, returning deep copies, `[]()()`s, std::bind, simd
and OMP when he talks about purity, lambdas, currying and parallelization.
What do you understand?

~~~
charlysl
Thank you

