timothy.wright
Maybe we should just move the "Function Programming sucks too" argument over here where it will be more fun?
timothy.wright
Maybe we should just move the "Function Programming sucks too" argument over here where it will be more fun?
MandleBrotimothy.wright
Maybe we should just move the "Function Programming sucks too" argument over here where it will be more fun?
Both can be nice in moderation. Object hierarchies that are 2 levels deep, functional approaches when it doesn't kill performance or require a mess of code to do what needs doing.
There are some nice 'functional first' languages out there that make for a nice middle ground (F#, OCaml, Rust, many others I'm sure) that, if you put the GCC/Clang compiler brains on them for a couple years would be reasonably performant. Rust already is decent but still has some things missing (solid SIMD for instance) All of these languages allow you to drop out of functional land and just do loops and mutable variables whenever you want with no fuss.
I've been doing some experiments with F# vs C lately and had some interesting results, where I can get very close to C level performance with functional approaches to number crunching on arrays - but, I have to roll my own fold/map operations. The core libs aren't marked as inline, the compiler isn't smart enough to inline them automatically if it is small. The compiler won't vectorize a loop, ever, so you have to do that by hand. The core libs don't use lazy evaluation so stringing list operations together iterates over them multiple times, etc. You can fix all of this if you roll your own map/fold/reduce etc operations for Arrays but...if you have to do that, why bother using a functional language? You can roll these things in C too.
whereas the very most obvious C code, a for loop with the operations I want in it compiles straight to automatically vectorized code that is super fast. There is no reason the same couldn't be true for F#, if the .NET JIT team made performance a priority, and the F# compiler team made performance a priority. This is an example of where someone using the language might say "Man F# is slow, probably because garbage collection or because virtual machine", but no, really it is because the ecosystem don't put performance at a really high priority. So the obvious F# code is ~5 times slower than the obvious C code. The clever F# code is just 1% slower. That gap between 5x and 1% could be erased, and the universe would be better. The gap should be even smaller with OCaml (natively compiled) and smaller again with Rust (no GC) if they can mature.
Apologies for the random stream of consciousness.
1 2 3 4 5 | double sum = 0.0; for (int i = 0; i < COUNT; i++) { double v = values[i] * values[i]; //square em sum += v; } |
1 2 3 4 | let sum = values |> Array.map square |> Array.sum |
1 2 3 4 | let sum = values |> Stream.map square |> Stream.sum |
1 2 3 | let sum = values |> Array.fastReduce addAndSquare |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | static member inline SIMDFold f h (start:'T) (values : 'T[]) = let mutable i = 0; let mutable v = Vector<'T>(start) while i < values.Length - Vector<'T>.Count do v <- f v (Vector<'T>(values,i)) i <- i + Vector<'T>.Count i <- 0 let mutable result = start while i < Vector<'T>.Count do result <- h result v.[i] i <- i+1 result let sum = values |> Array.SIMDFold addAndSquare (+) 0.0 |
Carmack
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.
.
.
.
C++ doesn't encourage functional programming, but it doesn't prevent you from doing it, and you retain the power to drop down and apply SIMD intrinsics to hand laid out data backed by memory mapped files, or whatever other nitty-gritty goodness you find the need for.
timothy.wright
I have yet to find a single example of a function program out in the wild that was just as good as the same program in C, let alone an order of magnitude better.
timothy.wright
Every one I have used had to "cheat" and use state somewhere, and ultimately ended up a complicated, un-debuggable pile of code.
1 2 3 4 5 6 7 | void someFunc (int x) { //operations on x here if (x < 1) return x //more operations on x here return x } |
1 2 3 4 5 6 7 | let someFunc x = //operations on x if x < 1 then return x else //more operations on x here x |
1 2 3 4 5 6 7 | let foo = if x < 1 then "small" else if x > 10 then "large" else "just right" |
1 2 3 4 5 | let foo = match x with | x when x < 1 -> "small" | x when x > 10 -> "large" | _ -> "just right" |