So, deep down in the guts of the language's libraries there must be mutable operations. Which kind of defeats the whole point.
I don't get point of functional programming. Machines don't work that way.
FP is useful because it provides an abstracted model that is pretty easy to reason about. It doesn't matter how it gets implemented, that's the point of the abstraction.
We don't write programs for machines to understand. We write programs for humans to understand.
True, but that program ends up executing on a machine. You normally want that program to execute as efficiently as possible. 'Efficiency' can be measured several ways... time to complete, resources required, financial cost.
A case in point is our company switched from using Cassandra (JVM based) to ScyllaDB (a C++ clone of Cassandra). Query latencies were the same if not faster, and we needed fewer nodes to handle the same load. All because the language used has some mechanical sympathy for the CPU it's going to run on, and no GC.
I see Scala is somewhat the defacto language used for 'big data' stuff. I have no idea why. I reckon if some bean counter translated that choice into $$$ things would change.
No, you normally want that program to execute efficiently enough to do its required job. Abstractions are often necessarily costly, but that's ok because their value is greater than their cost. Otherwise, you'd just throw all the abstractions away and use assembler.
> Query latencies were the same if not faster, and we needed fewer nodes to handle the same load. All because the language used has some mechanical sympathy for the CPU it's going to run on.
It seems like there's a whole load of reasons why it might have been more efficient on ScyllaDB that are unrelated to what language it was written in. Maybe the software design fit your requirements better? Maybe it was just better implemented? Maybe it was easier to configure for your load? Etc. etc. Programs aren't magically "more efficient" because they're written in C.
Since we are not quite there yet, could you explain in broad terms how a large collection is sorted while maintaining performance and immutability.
There will of course be "impure" writes at the machine level, but at the language level, the abstraction doesn't leak.
It seems like you're saying that abstractions are worthless unless they're perfect, which is obviously not true.
> Since we are not quite there yet, could you explain in broad terms how a large collection is sorted while maintaining performance and immutability.
What do you mean by "maintaining performance"? Relative to what? Who's asking for the sorted collection? How are they going to access it? What are the resource constraints? Give me a real-world example.
Don't get me wrong, I'm not saying that FP is the answer to everything. It's a useful tool, and part of being good at software development is knowing what tools to use and when.
Also, along the same lines, it is certainly possible to craft types in some FP languages which allow for this same logic to be captured, mostly via some monad construct.
Many believe the portable Assembler story and aren't aware that ISO C is defined in terms of an abstract machine.
The abstraction level that functional programming allows for, all the way back to Lisp, is to take advantage of the underlying hardware without being forced to hand code lowlevel details.
Something written in ML like language could be running on 70's, 80's, NUMA architectures, GPGPU, whatever, without changing one single line of code. Naturally we are not speaking about the same runtime implementation.
Whereas a language like C, requires a bunch of dialects to actually make use of the low level details, only exposed via Assembly and not part of ISO C.
And you can actually USE these low level details if you really want, with very low friction (if you are willing to lock down to specific architectures). Are you STILL whining?
C level (or Pascal if you're masochistic) is still a very nice abstraction, and for a lot of people it's everything they care about 99% of the time, to get all the control they need, while simultaneously ensuring they're not wasting any time fighting pointless language features that are mutually incompatible.
In the end everybody's using whatever they like. https://twitter.com/fabynou/status/1242517783092400129
There is no advantage in sorting a billion numbers the functional way.
There is an advantage to gain, though, when the unsorted numbers are used for other purposes besides sorting. Then, functional programming demands that the output of sorting is written to a new 1-billion array instead of "in place", so other clients can consume the same array in parallel without being disturbed by the sorting.
> So, deep down in the guts of the language's libraries there must be mutable operations. Which kind of defeats the whole point.
It doesn't defeat the point if the abstraction doesn't leak. If a pure functional language offers sorting as a pure primitive, then language-wise it doesn't matter that it actually mutates memory internally.
The problem with "mostly" pure functional languages is that the abstraction leaks enough to make it useless.
Does this make e.g. erlang useless? Processes have mutable dictionaries and you can perform I/O anywhere in your functions..
A key premise of functional programming is that the constraints of immutable semantics free the compiler up to do all sorts of performance optimizations, and the compiler can apply those optimizations much faster than a human developer can.
Also, when you really need a vector that you can mutate in place, you can still do that. Haskell has a mutable vector type. It's not the default idiom, but if you needed to sort a billion numbers in place, this is what you would use. Note all the function names prefixed with "unsafe": https://hackage.haskell.org/package/vector-0.12.1.2/docs/Dat...
>So, deep down in the guts of the language's libraries there must be mutable operations. Which kind of defeats the whole point.
Why does it defeat the point? If you can guarantee that the mutability doesn't leak (there are ways to do this), it behaves just like a pure implementation.
In fact, some structures that lend themselves to immutability represent the hardware better. Take your vector of a billion elements. It probably is too big for L1/L2 cache. Is it actually a billion things next to each other in memory? Not at all.
If you used something like a radix balanced balanced tree to represent your vector, you get amortized O(1) access and mutation can be implemented using copy on write at individual leaves of the tree. And your abstraction is much friendlier with the cache, because it reflects how the hardware works much better than a simple vector.
In practice, immutable data structures can be much more performant at scale than pretty much anything. They're not just convenient for soundness. Trivial data structures like vectors are really only useful when you're talking hundreds to the low thousands of elements, at which point who cares how much memory they take up?