Why Isn't Functional Programming the Norm? [video]

7 years ago (youtube.com)

The top comment on YouTube raises a valid point:

> I've programmed both functional and non-functional (not necessarily OO) programming languages for ~2 decades now. This misses the point. Even if functional programming helps you reason about ADTs and data flow, monads, etc, it has the opposite effect for helping you reason about what the machine is doing. You have no control over execution, memory layout, garbage collection, you name it. FP will always occupy a niche because of where it sits in the abstraction hierarchy. I'm a real time graphics programmer and if I can't mentally map (in rough terms, specific if necessary) what assembly my code is going to generate, the language is a non-starter. This is true for any company at scale. FP can be used at the fringe or the edge, but the core part demands efficiency.

  • In terms of performance, the way we build applications today is such a low bar that IMO it opens the door for functional programming. Even if it is not as fast as C or raw assembly - if it is significantly faster than Electron, but preserves the developer ergonomics... it can be a win for the end user!

    I created an Electron (TypeScript/React) desktop application called Onivim [1] and then re-built it for a v2 in OCaml / ReasonML [2] - compiled to native machine code. (And we built a UI/Application framework called Revery [3] to support it)

    There were very significant, tangible improvements in performance:

    - Order of magnitude improvement in startup time (time to interactive, Windows 10, warm start: from 5s -> 0.5s)

    - Less memory usage (from ~180MB to <50MB). And 50MB still seems too high!

    The tooling for building cross-platform apps on this tech is still raw & a work-in-progress - but I believe there is much untapped potential in taking the 'React' idea and applying it to a functional, compile-to-native language like ReasonML/OCaml for building UI applications. Performance is one obvious dimension; but we also get benefits in terms of correctness - for example, compile-time validation of the 'rules of hooks'.

    - [1] Onivim v1 (Electron) https://github.com/onivim/oni

    - [2] Onivim v2 (ReasonML/OCaml) https://v2.onivim.io

    - [3] Revery: https://www.outrunlabs.com/revery/

    - [4] Flambda: https://caml.inria.fr/pub/docs/manual-ocaml/flambda.html

    • Brilliant. Haskell was standing outside the door not until it was good enoguh to be an industry standard, but until industry standards dropped so low that it became competitive!

    • Hey, and good luck with revery :) I am doing something very similar but I wouldn't ever consider any GC language for the low-level part.

      I want to write UI in javascript because it's really nice language for prototyping but I also want it to be fast and javascript is unpredictable. Now, this might not be the case with OCAML but no matter what optimizations your compiler (or JIT interpreter) can do, you're still living in a lie, it's still some abstraction which is going to leak at some point.

      I've recently removed quite a lot of rust dependencies (wrappers) and the speedup is very noticable, it's because abstractions always come with a cost and you can't just pretend you're living in a rainbow world.

      BTW: you're not going to get much lower than 50M, cocoa has some overhead (10M IIRC), node has too (20M) and OCaml GC needs some heap too, and if you have any images, you need to keep them somewhere before sending to the GPU and GC to be fast needs to keep some mem around so that allocs are faster than just plain malloc.

      BTW2: in rust world, it's common to see custom allocators and data-oriented programming because it starts to get noticeable and this is hard to do if you can't reason about memory.

      If anyone is interested too, here's a repo https://github.com/cztomsik/graffiti

    • I couldn't have said it better myself. Thx for those links! And, yes, the compiler's flambda variant is an exquisite delight.

    • Is it fast because native & types or fast because of other reasons? The speed hierachy I've found goes: dynamic types w/ GC = 8x slower than C, static types w/ GC = 3x slower than C & static types w/ hybrid memory management like reference counting = 2x slower than C.

    • Does Revery use a native toolkit (winforms, gtk, etc) or is it also a webview like electron?

      I've seen a couple of gui toolkits in rust following the Elm architecture and I think it's an amazing idea. It would be great if I was able to create apps like this using something like Qt behind the scenes.

      1 reply →

  • > FP will always occupy a niche because of where it sits in the abstraction hierarchy

    At some point in history, people stopped worrying about not understanding compilers, how they allocate registers and handle loops and do low-level optimizations. The compilers (and languages like C or C++) became good enough (or even better than humans in many cases) in optimizing code.

    The same happened with managed memory and databases, and it will happen here, too. Compilers with FP will become good enough in translating to the machine code so that almost nobody will really care that much.

    The overall historical trend of programming is more/better abstractions for humans and better automated tools to translate these abstractions into performant code.

    • Some people stopped worrying about not understanding compilers. They're not working on drivers, realtime (esp where low lag & jitter are concerned such as motion control), or high performance software of all stripes, trying to squeeze the most out of the available hardware. It's all about choosing the right tool for the job, and there is no right tool for every job. A guy generating sales reports has very, very different needs from the lady writing a rendering engine.

      Michael Abrash (graphics programmer extraordinaire) said it best, and I'll paraphrase: the best optimizing compiler is between your ears. The right algorithm beats the pants off the most optimized wrong algorithm. Or, as i like to say "there is nothing faster than nothing" -- finding a way to avoid a computation is the ultimate optimization.

      And managed memory is wonderful, almost all the time. That is, just until the GC decides to do a big disposal and compaction right in the middle of a time-sensitive loop causing that thing that "always works" to break, unpredictably, due to a trigger based on memory pressure. Been there, done that. If it's a business report or a ETL, big deal. If it's a motor-control loop running equipment, your data or machinery is now trash.

      For most of the programming world, and I count myself in this group, the highly abstracted stuff is great. Right up until the moment where something unexpected doesn't work then it turns in to a cargo cult performance because it's nearly all black-box below. Turtles, all the way down.

      There is value in understanding the whole stack, even today.

      5 replies →

    • Programming is has grown so much as a field that generalizations like this rarely capture the truth.

      It's true that in many domains, people care much less about performance than they used to.

      At the same time, other people care a lot more about performance. Programming is just big and diverse.

      The end of single score scaling is one big reason it's more important than ever.

      Another reason is simply that a lot more people use computers now, and supporting them takes a lot of server resources. In the 90's there were maybe 10M or 100M people using a web site. Now there are 100M or 1B people using it.

      I think there's (rightly) a resurgence in "performance culture" just because of these two things and others. CppCon is a good conference to watch on YouTube if you want to see what people who care about performance are thinking about.

      ----

      If you're writing a web app, you might not think that much about performance, or to be fair it's not in your company's economics to encourage you to think about it.

      But look at the hoops that browser engineers jump through to make that possible! They're using techniques that weren't deployed 10 years ago, let alone 20 or 30 years ago.

      Somebody has to do all of that work. That's what I mean by computing being more diverse -- the "spread" is wider.

      6 replies →

    • > At some point in history, people stopped worrying

      Did they ? Because I keep seeing people around me who want to get into FPGA programming because they aren't getting enough juice from their computers. Sure, if you're making $businessapp you don't care but there is a large segment of people who really really really really want things to go faster, with no limits - content creation, games, finance... hell, I'd sell a rib for a compiler that goes a few times faster :-)

      1 reply →

    • Fun fact: C used to be considered a high-level language. Now everyone talks about it being "close to metal" which to olds like me is a dead give-away the person either doesn't know C or doesn't know the "metal". Most of the stuff people think of as being the "metal" in C are, in many cases, virtual abstractions created by the operating system. Embedded development w/o dynamic memory allocation less so... but that's not what most people are talking about.

      14 replies →

    • 99% of the time you can forget about them, but when you get performance problems then you need to start digging in to what goes on behind the scenes.

    • Some engineers have terminal systems brain. That's a rude way for me to say it, but I have met engineers who feel the need to fully understand how code maps to hardware otherwise they don't feel comfortable.

  • I regularly read the assembly output of the OCaml compiler I'm using and there are very few surprises. The mapping from source to generated assembly is quite straightforward. You couldn't say the same for Haskell, though. So it depends on which FP language you're using.

    • Does OCaml give you enough tools to optimize around things like CPU-cache and memory management costs? It's one thing to know what kind of assembly is going to be produced by a block of code, but it's another thing to be able to get the machine to do exactly what you want.

      6 replies →

    • Actually I’ve found it pretty easy to track / reason about. But I guess I do have a decent mental model for how the compiler works

  • I too have been programming professionally for nearly two decades. Much longer if you consider the time I spent making door games, MUDs, and terrible games in the 90s.

    I think functional programming gives you powerful tools to reason about the construction of programs. Even down to the machine level it's amazing how amortized functional data structures change the way you think about algorithmic complexity. I think laziness was the game changer here. And if you go all in with functional programming it's surprising how much baseline performance you can get with such little effort and how easy it is to scale to multiple cores and multiple hosts.

    There are some things like vectorization that most functional languages I know of are hard pressed to take advantage of so we still reach out to C for those things.

    However I think we're starting to learn enough about functional programming languages and how to make efficient compilers for them these days. Some interesting research that may be landing soon that has me excited would enable a completely pure program to do register and memory mutations under the hood, so to speak, in order to boost baseline performance. I don't think we're far off from seeing a dependently typed, pure, lazy functional language that can have bounded performance guarantees... and possibly be able to compile programs that don't even need run time support from a GC.

    I grew up on an Amiga, and later IBM PCs, and that instinct to think about programs in terms of a program counter, registers, and memory is baked into me. It was hard to learn a completely different paradigm 18 or so years into my professional career. And to me, I think, that's the great accident that prevented FP from being the norm: several generations were simply not exposed to it early on on our personal computers. We had no idea it was out there until some of us went to university or the Internet came along. And even then... to really understand the breakthroughs FP has made requires quite a bit of learning and learning is hard. People don't like learning. I didn't. It's painful. But it's useful and worth it and I'm convinced that FP will come to be the norm if some project can manage to overcome the network effects and incumbents.

    • I would agree with this, I came up in the same time period and we just programmed closer to the metal in that period, we did not have the layers and it was just normal to think in terms of the machines hardware (memory addresses, registers, interrupts, clock, etc.) This naturally leads to a procedural way of thinking, variables where a think veil over the actual memory they addressed.

      It actually takes a lot of unlearning to let go of control of the machine and let it solve the problem, when you are used to telling it how to solve the problem. I came to that conclusion when I dabbled in ProLog just to learn something different, and I had a really hard time getting my head around CL when I first got into it, due to wanting to tell then machine exactly how to solve the problem. I think it was just ingrained in those of us that grew up closer to the metal and I think the Byte magazine reference, in the talk, has a lot to do with it, we just did not have that much exposure to other ideas, given that mags and Barns and Noble, where our only source to new ideas. That and most of us where kids just hacking on these things alone in our bedroom with no connectivity to anyone else.

      I remember before the web getting on newsgroups and WAIS and thinking how much more info was available that the silo'ed BBS we used to dial into. Then the web hit and suddenly all of these other ideas gained a broader audience.

    • OTOH, think of the vast hordes of new developers exposed to lot's of FP and NOT having that background in Amiga and PC and bare-metal programming that you do.

      FP has been largely introduced into the mainstream of programming through Javascript and Web Dev. Let that sink in.

      End of the day, the computer is an imperative device, and your training helps you understand that.

      FP is a perfectly viable high-level specification or code-generational approach, but you are aware of the leaky abstraction/blackish box underneath and how your code runs on it.

      I see FP and the "infrastructure as code" movement as part and parcel to the same cool end reality goal, but I feel that our current industry weaknesses are related to hiding and running away from how our code actually executes. Across the board.

      16 replies →

    • I am fully on board with you.

      Learned to code in the mid-80's, Basic and Z80 FTW.

      Followed up by plenty of Assembly (Amiga/PC), and systems level stuff using Turbo Basic, Turbo Pascal, C++ (MS-DOS), TP and C++ (Windows), C++ (UNIX), and many other stuff.

      I was lucky enough that my early 90's university has exposed us to Prolog, Lisp, Oberon (and its descendants), Caml Light, Standard ML, Miranda.

      Additionally the university library allowed me to dive into a parallel universe from programming ideas that seldom reach mainstream.

      Which was great, not only did I learn that it was possible to marry systems programming with GC enabled languages, it was also possible to be quite productive with FP languages.

      Unfortunately this seems to be yet another area that others only believe on its possibilities after discovering it by themselves.

    • > Some interesting research that may be landing soon that has me excited would enable a completely pure program to do register and memory mutations under the hood, so to speak, in order to boost baseline performance. I don't think we're far off from seeing a dependently typed, pure, lazy functional language that can have bounded performance guarantees... and possibly be able to compile programs that don't even need run time support from a GC.

      Is there any more info/links available about this?

      1 reply →

  • Just wait until this guy has to use something like SQL or Spark. They will always occupy a niche for exactly these reasons. Turns out it's a pretty big niche though. So big in fact, that maybe we shouldn't call it a niche.

    Python's ecosystem is built on this premise. Let some other language (C) do the fast stuff and leverage that for your applications. It's not a niche language, even though you don't have direct control over things like memory management and GC.

    Perhaps the commenter's role of real time graphics programming is actually the niche.

    • re python and scripting, afaik used to be known as "glue languages". not sure how true it is anymore.

  • > This is true for any company at scale. FP can be used at the fringe or the edge, but the core part demands efficiency.

    I think things like real-time graphics are the exception not the rule. Most of the software run by users these days is in the context of a browser, which is implemented many layers of abstraction away from the machine. Much of the code running servers is also still interpreted scripting languages.

    Don't get me wrong, I wish a lot more software was implemented with performance in mind, because the average-case user experience for software could be so much better, but a ton of the software we use today could be replaced by FP and perform just as well or better.

  • Perhaps not a satisfactory response but when I start drifting towards thinking FP is fundamentally not as performant as _whatever_else_, I remember that Jane Street uses OCaml basically from top to bottom, and they certainly can't be too slow... Some black magic going on there.

    • The "oh no it's slow, and you can't reason about performance" FUD is mostly directed at Haskell's lazy evaluation, but people like to throw it vaguely in the direction of "FP" in general. Most of the performance problems you have in Haskell (as in this recent submission: https://ocaml.org/learn/tutorials/garbage_collection.html, though this might change if/when Multicore OCaml ever happens?). So if you write an innermost function that does arithmetic on stuff but never allocates data structures, you will not have GC problems because you will not have GC during that time, period.

      Also, there are cases where destructive mutation of things is more efficient than making pure copies. OCaml allows you to do that, you don't need to fiddle with monads to simulate state.

      There really isn't that much black magic there. Just don't believe everything that is said about "FP".

      7 replies →

    • Jane Street wrote a compiler that converts Ocaml to Verilog which they run on FPGAs. The OCaml you write in that case is pretty different than what you write for CPUs.

      11 replies →

    • There are really many places in code where you really don't care about performance that much. And in that case conciseness/expressiveness/correctness can be extremely valuable.

      Also there are different aspects to performance, and when (for example) it comes to latency, a platform like Erlang/BEAM makes it particularly easy to get low latency in certain contexts without thinking about implementation much. In Haskell you can accomplish similar things with green threads. It will probably need more clock cycles for a given action than a tuned C implementation but that's not always what matters, and the code will probably be cleaner.

    • Is the kind of HFT that Jane Street does that reliant on extremely low latency? A lot of HFT firms operate on the timescale of seconds, minutes, or even hours, not milliseconds.

      1 reply →

  • I’m all for mechanical sympathy, and I’m sure that some programmers legitimately need their language to map neatly to assembly, but that isn’t the norm as evidenced by the overwhelming popularity of interpreted and VM languages. Lots of companies are making money hand over fist with Python, which is probably 3 orders of magnitude (or more) slower than the optimized C or C++ that this real-time graphics engineer is writing.

    EDIT: Is this controversial? What are downvoters taking issue with? That Python is a very popular language? That it is much slower than C/C++?

  • Classic games programmer logic. I've heard it a billion times. "X feature abstracts the hardware and therefore I could never use it for programming in my tiny niche and therefore it could never become popular."

    And how many of the top 10 languages are running in a virtual machine? Which could be literally doing anything under the hood with your allocations, caching, etc?!

    There is nothing wrong with saying, I don't see this working out in my domain due to these concerns it's just silly to say, I never see it taking off because it can't work in my domain.

    I think this video nails it pretty dead on. My team works almost exclusively in C# these days for reasons mostly beyond our control. The team generally likes the language quite a bit (it's one of my personal favorites). But when I find myself asking for new features they come in two buckets. I'd like feature that help certain members of my team write less side effect heavy code and I'd like immutability by default with opt-in mutability. Basically I'd like more functional like features. But hey, that's what I see from my niche.

    • > And how many of the top 10 languages are running in a virtual machine? Which could be literally doing anything under the hood with your allocations, caching, etc?!

      VMs provide an environment, just like any other. Javascript articles are chock full of information on how to not abuse the GC by using closures in the wrong place. C#'s memory allocation is very well defined, Java has a million tuning parameters for their GC, Go is famous for providing goroutines with very well defined characteristics.

      Heck people who know C# can look at C# code and tell you almost exactly what the VM is going to do with it. And now days C# allows direct control over memory.

      People writing high performance code on Node know how the runtime behaves, they know what types of loads it is best for, none of that is a mystery.

      Sure some details like "when does this code get JITed vs interpreted" are left up to the implementation, but it isn't like these things are secret. I think every major VM out there now days is open source, and changes to caching behavior is blogged about and the performance implications described in detail.

      The fact is, all programming paradigms are merely ways to limit our code to a subset of what the machine can do, thereby making reasoning about the code easier.

      They are purely mental tools, but they almost all have a performance cost for using them. They are turing complete tools of course, any solution is theoretically solvable with any of the major paradigms, but not every paradigm is appropriate for every problem.

      So, you know, pick the paradigm that makes it easiest to reason about the problem space, given acceptable performance trade offs.

      1 reply →

  • >> This is true for any company at scale

    I do not think this is true outside your domain. Amazon uses Java, C++ and Perl. At the time I was there majority of the website code was in Perl. Amazon one of the biggest companies on the planet.

    • Amazon needed to create AWS to be able to run all that perl performantly (joke).

      Actually, a lot of programming language improvements have come from trying to make lisp performant.

  • Many functional languages acknowledge this and are not pretending to have low-level language facilities. Instead, they have built-in mechanisms (FFI) to interface with those low level languages whenever needed.

  • Are you suggesting that oop allows programmers to understand the assembly output?

    Did you watch the video? The most popular language is JavaScript, which is only not functional but a quirk of history.

    The video makes an argument for marketing being the reason.

    • JS isn't really a functional language, it's an imperative, prototype-based language with partial functional support that allows multiple coding styles, like most of the popular scripting languages.

      1 reply →

    • The fun, and funny, and maybe (probably) even terrible, thing about javascript is that while it -is- functional, and (IIRC) always has been, historically it wasn't originally used that way!

      Only relatively recently have programmers embraced its functional aspects; prior to that it was mostly used as a procedural language.

      Then people started to used functional aspects of it to "shoehorn" it into allowing a quasi-OOP form of programming style, and this form has been baked (in no small part) into the latest version of ECMAScript.

      But people following this path, coupled with (I believe) using JQuery, NodeJS, and other tools (and now React) have led most of them (raising hand here) to more fully embrace it as a functional language.

      But here's the thing:

      You can still use it as a procedural language - and an OOP language - and a functional language! All at the same time if you want - it doesn't care (much)! It's like this weird mismash of a language, a Frankenstein's Monster coupled to Hardware's killer robot.

      Yes - with today's Javascript you can still write a unicorn farting stars that follows your mouse on a webpage while playing a MIDI file - and do it all procedurally. In fact, there's tons of code examples out there still showing this method.

      You can mix in simple class-like constructs using anonymous functions and other weirdness - or just use the latest supported ECMAScript OOP keywords and such - go for it!

      Want to mix it up? Combine them both together - it don't care!

      Oh - and why not pass a function in and return one back - or an entire class for that matter! It's crazy, it's weird, it's fun!

      It's maddening!

      And yes - it's a crazy quirk of history - a language that was created by a single programmer over the course of a weekend (or so legend goes) at Netscape has and is seemingly taking over the world of software development.

      Not to mention Web Assembly and all that weirdness.

      I need to find an interview with that developer; I wonder what he thinks about his creation (which is greatly expanded over what he started with, granted) and it's role in software today - for good or ill...

      4 replies →

  • OK, but dismissing most of the things that people use computers for as "the fringe" is rather parochial.

    • I think he means more "the outer layers". For instance Alpha Go was written in Python at the outer layers. The core pieces doing the actual neural net work are low level libraries.

      Similarly, google search, at the outer most layers, is javascript, then probably some layer of Go or similar, but then the core is highly tuned C++ and assembler.

  • I had a programming languages survey class in college. The thrust of the course was different languages for different applications. It's not startling that the person, whose comment you quoted, doesn't find the functional paradigm helpful in graphics programming. Functional programming helps with expressiveness and reasoning, i.e. variables don't suddenly change on you when you're not expecting it.

    A video game programmer would probably not be helped because a big part of their coding, as I understand it, is wringing out every clock cycle and byte of memory possible. However, the programmer writing the AR/AP system that allows tracking for in-game purchases would find OCaml, for instance, very beneficial.

  • Unless you’ve written a modern, optimizing C/C++ compiler, you have absolutely no idea what kind of machine code a complex program is going to spit out. It’s not 1972 anymore, and C code is no longer particularly close to the metal. It hasn’t been for some time.

    • This is wrong, you absolutely can have an idea of what a C (and most of the time, C++) compiler will generate. You may not know the exact instructions, but if you are familiar with the target CPU you can have a general idea what sort of instructions will be generated. And the more you check the assembly that a compiler generates for pieces of code, the better your idea will be.

      Note that you almost never need to care about what the entirety of a "complex program" will generate - but often you need to care about what specific pieces you are working on will generate.

      The C language itself might be defined in terms of an abstract machine, but it is still implemented by real compilers - compilers that, btw, you also have control over and often provide a lot of options on how they will generate code.

      And honestly, if you have "absolutely no idea what kind of machine code" your C compiler will generate then perhaps it it will be a good idea to get some understanding.

      (though i'd agree that it isn't easy since a lot of people treat compiler options as wells of wishes where they put "-O90001" and compiler developers are perfectly fine with that - there is even a literal "-Ofast" nowadays - instead of documenting what exactly they do)

      6 replies →

    • Never written even a simple C compiler, but I, and most c++ programmers that care about performance I think, do have a decent idea what code g++ is going to generate.

      2 replies →

  • I've been programming for 34 years - 25 of those professionally. In the early days of my programming life it was super important to know how the code would run on the metal (and much of my time was spent writing assembler for that reason). Processors were slow, memory access was slow, and memory quantity was small (32k on my first computer). I spent a decade in the games industry building graphics engines and hand interleaving assembler to get the maximum amount of juice out of whatever console I was writing for (I beat what Sony said their Playstation 1 could actually do).

    Then OOP happened and much of the early guarantees about how something ran went away, abstraction everything meant we couldn't reasonably know what was happening behind the scenes. However, that wasn't the biggest issue. Performance of CPUs and memory had improved significantly to the point where virtual method calls weren't such a big deal. What was becoming important was the ability to manage the complexity of larger projects.

    The big deal has come recently with the need to write super-large, stable applications. Sure, if you're writing relatively small applications like games or apps with limited functionality scope, then OOP still works (although it still has some problems). But, when applications get large the problems of OOP far outstrip the performance concerns. Namely: complexity and the programmer's inability to cognitively deal with it.

    I started a healthcare software company in 2005 - we have a web-application that is now in the order of 15 million lines of code. It started off in the OOP paradigm with C#. Around 2012 we kept seeing the same bugs over and over again, and it was becoming difficult to manage. I realised there was a problem. I (as the CTO) started looking into coping strategies for managing large systems, the crux of it was to:

    * Use actor model based services - this helped significantly with cognition. A single thread, mutating a single internal state object, nice. Everyone can understand that.

    * Use pure functional programming and immutable types

    The reason pure functional programming is better (IMHO) is that it allows for proper composition. The reason OOP is worse (IMHO) is because it doesn't. I can't reasonably get two interfaces and compose them in a class and expect that class to have any guarantees for the consumer. An interface might be backed by something that has mutable state and it may access IO in an unexpected way. There are no guarantees that the two interfaces will play nicely with each other, or that some other implementation in the future will too.

    So, the reality of the packaging of state and behaviour is that there's no reliable composition. So what happens is, as a programmer, I'd have to go and look at the implementations to see whether the backing types will compose. Even if they will, it's still brittle and potentially problematic in the future. This lack of any kind of guarantee and the ongoing potential brittleness is where the cognitive load comes from.

    If I have two pure functions and compose them into a new function, then the result is pure. This is ultimately (for me) the big deal with functional programming. It allows me to not be concerned about the details within and allows stable and reliable building blocks which can be composed into large stable and reliable building blocks. Turtles all the way down, pure all the down.

    When it comes to performance I think it's often waaaay overstated as an issue. I can still (and have done) write something that's super optimised but make the function that wraps it pure, or at least box it in some way that it's manageable. Because our application is still C# I had to develop a library to help us write functional C# [1]. I had to build the immutable collections that were performant - the cost is negligible for the vast majority of use-cases.

    I believe our biggest problem as developers is complexity, not performance. We are still very much working with languages that haven't really moved on in 20+ years. Yes, there's some improvements here and there, but we're probably writing approximately as many lines of code to solve a problem as we were 20 years ago, except now everyone expects more from our technology. And until we get the next paradigm shift in programming languages we, as programmers, need coping strategies to help us manage these never-ending projects and the ever increasing complexity.

    Does that mean OOP is dead as an idea? No, not entirely. It has some useful features around extensible polymorphic types. But, shoehorning everything into that system is another billion dollar mistake. Now when I write code it always feels right, and correct, I always feel like I can trust the building blocks and can trust the function signatures to be honest. Whereas the OOP paradigm always left me feeling like I wasn't sure. I wish I'd not lost 10+ years of my career writing OOP tbh, but that's life.

    Is functional programming a panacea? Of course not, programming is hard. But it eases the stress on the weak and feeble grey matter between our ears to focus on the real issue of creating ever more impressive applications.

    I understand that my reasons don't apply to all programmers in all domains. But when blanket statements about performance are wheeled out I think it's important to add context.

    [1] https://github.com/louthy/language-ext

  • After Minecraft, none of this makes any sense anymore. That is a genre-defining cultural masterpiece and runs on the JVM which is fosbury-flopping all over your registers on purpose. And everyone used to repeat some folk wisdom about Java back then.

  • I had some truly dismal experiences with code generators in the 90's. At one point I blamed code generation itself, automatically dismissed any solution out of hand, and was proven right quite a few times.

    It wasn't until I used Less on a project that I encountered a generator that did what I expected it to do in almost every situation. It output essentially what I would have written by hand, with a lot less effort and better consistency.

    I expect people who adopted C felt roughly the same thing.

    People presenting on OOAD occasionally warn about impedance mismatches between the way the code works and the way you describe it[0]. If what it 'does' and how you accomplish it get out of sync, then there's a lot of friction around enhancements and bug fixes.

    It makes me wonder if this is impossible in FP, or just takes the same degree of care that it does in OO.

    [0] a number of cow-orkers have 'solved' this problem by always speaking in terms of the code. Nobody has the slightest clue what any of them are talking about 50% of the time.

  • I agree. I haven’t done a lot of FP but, as a person who is used to knowing how my code will be executed, I find it very difficult to map what I want the machine to do onto functional code.

    Functional Programming might have great advantages in correctness but sooner or later the code is going to be run on a real CPU with real instructions and all the mathematical abstractions don’t mean much there.

    That said, I can see they have their place for specialized areas.

  • The exact same could be used to describe SQL/Bash/Lua etc, which sometimes used by accountant/admin/game designer. Those languages are at the sometimes at the edge of the systems, but obviously not non-starter.

  • But it should be fine, then, as a replacement for anything written in Javascript, Ruby, Python, etc.

    (Also, addressed in the video at the end, answering an audience member question.)

  • > core part demands efficiency

    what about development efficiency? maintenance efficiency? developer onboarding efficiency? there are many efficiencies companies care about.

  • I'm a true believer that with C++ and lots of scary templates you can do FP that maps exactly on what you want it to be doing.

  • Sure for hardware, real time, embedded use cases (and probably others), makes sense.

    Does it matter for data analysis and most web apps, infra as code, etc? Which data scientists do you know fetishize how Python is laying out memory?

    OOP is a hot mess. Yes, I know, you’re all very well versed in how to use it “right”, but the concept enables a mess. It’s the C of coding paradigms when it would be great to have a paradigm that pushes towards Rust, and reduces the chance for hot messes from the start.

    Most of this work is organizing run of the mill business information. Why it works from a math perspective is more universally applicable and interesting anyway.

  • With JavaScript as the most popular language out there I would say that this low level core stuff is now the fringe.

EDIT: I wrote this comment before watching the video. I stand by this comment, but the video is very good and I wholeheartedly agree with its conclusions.

As someone who writes pure FP for a living at a rather large and well known org, these threads physically hurt me. They're consistently full of bad takes from people who don't like FP, or haven't written a lick of it. Subsequently, you get judgements that are chock full of misconceptions of what FP actually is, and the pros and cons outsiders believe about FP are completely different from its practitioners. It's always some whinge about FP not mapping "to the metal", which is comical given say, Rust's derivation from what is quite functional stock.

My personal belief? We just don't teach it. Unis these days start with Python, so a lot of student's first exposure to programming is a multi-paradigm language that can't really support the higher forms of FP techniques. Sure, there may be a course that covers Haskell or a Lisp, but the majority of the teaching is conducted in C, C++, Java or Python. Grads come out with a 4 year headstart on a non-FP paradigm, why would orgs use languages and techniques that they're going to have to train new grads with from scratch?

And training people in FP is bloody time consuming. I've recorded up to 5 hours of lecture content for devs internally teaching functional Scala, which took quadruple the time to write and revise, plus the many hours in 1-on-1 contact teaching Scala and Haskell. Not a lot of people have dealt with these concepts before, and you really have to start from scratch.

  • What a coincidence. This sounds exactly like what happens with OOP. Every discussion here gets swarmed with clueless people who think Java is the apex of OO programming, because that's what gets taught in universities these days. They don't understand any of the core concepts that prompted Xerox Park to develop the OO paradigm in the first place. They aren't aware of any of the relevant research. They operate under the assumption that OO was born out complete ignorance of functional programming, even though people who kick-started its rise were keenly aware of Lisp (for example, Alan Kay frequently references McCarthy's work and research papers in his talks). Etc, etc.

    • Good OOP is good FP - they swim in the same water. composition, generics/adt's, elegance, encapsulation...

      In it's ideal form it's about taming the metal like a trick pony.

      I'm nowhere near that level, being a fortran in any language sorta guy lol, but when I see well-built stuff, I take notes. Matryushka dolls, lol

      Kay et al were swimming in the same water as Hewitt etc, conceptually. He said that the key takeaway from OOP was objects passing messages (actor model), not so much the inheritance story (the composition)

      but yes, they all criss-cross there

    • I think the Smalltalk paradigm is deeply defective and the Actor model (the purest form of OOP to my mind) remedies most of its faults but perpetuates some others. A few flaws:

      - Modeling all communication as synchronous message-passing. Some communication (such as evaluating mathematical functions) is naturally modeled as synchronous procedure calls, while communication which is naturally modeled as message-passing should be asynchronous by default (to address unpredictable latency, partial failure, etc.).

      - Emphasizing implementation inheritance as the primary means of code reuse. This is now generally acknowledged to be a mistake, so I won't elaborate.

      - Deferring all method resolution to runtime. This makes the amazing introspective and dynamic capabilities of Smalltalk possible, but it also makes it impossible to statically verify programs for type-correctness.

      - Relying on mutable local state rather than explicit, externalized state. This is controversial, and it's a defect of the Actor model as well (yes, passing new parameters into a tail-recursive message receive loop is equivalent to mutating local state). The partisans of OOP and the Actor model believe this to be a virtue, enabling robust emergent collective behavior from small autonomous software agents, but it makes predicting large-scale behavior difficult and debugging nearly impossible.

      2 replies →

    • > Every discussion here gets swarmed with clueless people who think Java is the apex of OO programming, because that's what gets taught in universities these days.

      Realistically, Java (or something very much like it) is the apex of OOP, at least as most people will experience it. The Ur-example of OOP might be a beautiful, internally consistent vision of mathematical purity, but most of us will never experience it.

      Similarly, Agile-fall is the most common form of Agile that people will experience, which is why we always fall into "no true Scotsman" territory when ~~arguing about~~ discussing it.

      There is, I think, a disconnect between people who are primarily concerned with the beauty of software - simple models, elegant algorithms, and so on - and the people who are primarily concerned with getting their feature branch merged to master so their manager will let them go to their kid's soccer game.

      The beauty of software is important, and there's value in trying to bring the useful, but more esoteric concepts of CS into the mainstream, but at the same time we need to be aware of the ground truth of software development.

      2 replies →

    • The thing about these discussions is they seem to have two different questions mixed together. One question is "what's the best way to produce good software in a circumstance where everyone start on top of their game and the right thing" and the other is "what's a sort-of natural, slightly better average, way that programming can be." The answer to the first can be "Good functional Programming" or "Good OOP" or maybe something even more exotic. But it doesn't matter that much for the second question. Because usually the question of "how can this code we have already be better" mean "how do you take a general mess and make salvagable?" I don't know what the FP's answer to this is. I generally get the feel the FP people don't want to have an answer to this because then there'd be a lot of better-but-still-bad installations out there. But there are plenty answers to improvement using OOP - most say just encapsulate everything or similar things. All sorts of things can be thinly encapsulated, better, but still far from good. That seems to me explain the prevalence of OOP.

  • >My personal belief? We just don't teach it.[...] Grads come out with a 4 year headstart on a non-FP paradigm,

    I don't agree the lack of proactive education is the reason FP isn't the norm. Your conclusion doesn't take into account the counterfactuals:

    - C Language took off in popularity despite BASIC/Pascal being the language more often taught in schools

    - languages like PHP/Javascript/Python/Java all became popular even though prestigious schools like MIT were teaching Scheme/Lisp (before switching to Python in 2009).

    You don't need school curricula to evangelize programming paradigms because history shows they weren't necessarily the trendsetters anyway.

    On a related note, consider that programmers are using Git DVCS even though universities don't have formal classes on Git or distributed-version-control. How would Git's usage spread with everybody adopting it be possible if universities aren't teaching it? Indeed, new college grads often lament that schools didn't teach them real-world coding practices such as git commands.

    Why does Functional Programming in particular need to be taught in schools for it to become a norm but all the other various programming topics do not?

    • > Why does functional programming need to be taught in schools but all the other various programming topics did not?

      Because I think it is harder for people who have programmed with other paradigms - following an inverse law, most things should get easier to learn with experience, not harder. It's foreign, it's weird, it's back to front. It doesn't have an immediately obvious benefit to what people are used to, and the benefits it has come at scale and up against the wall of complexity (in my opinion). It's hard to adopt upfront. At the small scale it's often painful to use. The syntax is weird. It's aggressively polymorphic, reasoning in abstractions rather than concretions. I could go on (and yet I still adore it).

      The only reason FP has been successful as it is, is because its evangelists are incredibly vocal, to the point of being fucking annoying sometimes. It's had to be forced down people's throats at times, and frankly, there's no better place to force a paradigm down someone's throats than at a university, where non-compliance comes at academic penalty, and when the mind is most impressionable.

      16 replies →

    • > C Language took off in popularity despite BASIC/Pascal being the language more often taught in schools

      While C is less constrained, it's structurally very similar to Pascal; they don't differ in paradigm and are in the same syntax family.

  • >Subsequently, you get judgements that are chock full of misconceptions of what FP actually is

    I put the blame for that squarely on the Haskell cultists. They've caused everyone to have the impression that functional programming needs to have esoteric syntax and lazy evaluation by default.

    It's like how the Java cultists have ruined OOP.

  • I think you nailed it. But FP proponents have done a fair bit of harm to the paradigm itself in that some of the more osutspoken proponents have been pretty alienating. They've pushed the language superiority argument to death. They should probably be focused on pushing the style in the hopes that the next round of popular languages begins to implement FP style as first class features. Which is of course what the author alludes to and I think is actually happening. Which would jive with history.

    A lot of what became OO language features arose because people were already using the style in non-OO languages. C being a great example of how you can use a ton of C++ like features, you best end up writing a lot of boiler plate to hook up function pointers and the like.

    Going back further we see features in C were being implemented by assembly prigrammers as macro assembly. So the pattern the author puts forward has basically held true for multiple shifts in programming paradigms.

    Which leaves me with one point of contention with the presenter. That OO dominance is not happenstance. And neither was the fact that lots of people were writing OO style C. There is something about OOP that helped people think about their code easier. That's why they adopted the features. Maybe not everything about it was great and we're learning that. But it genuinely helped people. Just as English language oriented languages helped people over ASM.

  • Personally, I get frustrated that there seems to be a belief that you can only use FP or OOP, when the reality is both models can be used in conjunction, and there may be reasons to choose one over the other dependent on what you are doing. Not to mention there are other models such as Protocol Oriented Programming. You see this in languages like Swift.

    • The issues is that you get benefits for sticking to one paradigm, because then everything is made of the same stuff.

      If everything is an object, then you can use all your tooling that works with objects, which is everything. If everything is pure, you get easy parallelism. If everything is an actor, you get easy distributability. If everything is a monad or function, you get easy compositionality. The list goes on. Smalltalk, Erlang and Haskell are languages with very dedicated fan bases, which I theorise is because they went all in on their chosen paradigm.

      2 replies →

Richard Gabriel’s famous essay “Worse is better” (https://www.jwz.org/doc/worse-is-better.html) is an interesting perspective on why Lisp lost to C. In a way, the same arguments (simplicity vs consistency vs correctness vs completeness) can be made for why functional programming lost to OOP.

But those philosophical perspectives aside, personally I find my brain works very much like a Turing Machine, when dealing with complex problems. Apart from my code, even most of my todos are simple step-by-step instructions to achieve something. It’s easily understandable why like me, other non-math folks would prefer a Turing Machine over Lambda Calculus’ way of writing instructions.

This could be why OOP/Imperative was often preferred over FP.

  • > personally I find my brain works very much like a Turing Machine

    Exactly this. How baking a cake in FP looks like:

    * A cake is a hot cake that has been cooled on a damp tea towel, where a hot cake is a prepared cake that has been baked in a preheated oven for 30 minutes.

    * A preheated oven is an oven that has been heated to 175 degrees C.

    * A prepared cake is batter that has been poured into prepared pans, where batter is mixture that has chopped walnuts stirred in. Where mixture is butter, white sugar and brown sugar that has been creamed in a large bowl until light and fluffy

    Taken from here: https://probablydance.com/2016/02/27/functional-programming-...

    • I actually don't know of any functional programming languages that don't have syntactic and semantic support for writing step-by-step algorithms.

      5 replies →

    • Okay, so first of all this is an excellent joke. But it's not that great of an analogy.

      This quote chooses one of many FP syntaxes. It's cherry picking. It uses "a = b where c = d." That's equivalent to "let c = d in a = b." Let will allow you to write things like:

          let
              cake_ingredients = [butter, white sugar, sugar]
              batter = cream(ingredients=cake_ingredients,
                             dish=large_bowl,
                             condition=LIGHT_AND_FLUFFY)
              prepped_pans = pans_full_of(batter)
              oven = preheat(your_over, 175 C)
              cake = bake(cake, 30 minutes)
          in
              dessert_tonight = cooled(cake)
      

      This isn't where FP and imperative are different.

      What's really different is that the let statement doesn't define execution order. That's not so relevant to this part of the mental modeling though.

      I think it's great that I can choose between "let ... in ..." or "... where ...". In real life, for a complex bit of language, I happen to often like putting the main point at the top (like a thesis statement), then progressively giving more details. Mix and match however's clear.

      7 replies →

    • > How baking a cake in FP looks like:

      > * A cake is a hot cake that [...]

      The difference between a functional programmer and an imperative programmer is an imperative programmer looks at that and says “yeah, great takedown of FP”, while a functional programmer says, “what’s with the unbounded recursion?”

      But, more seriously, it's long been established that real programming benefits from use of both imperative and declarative (the latter including—but not limited to—functional) idioms, which is why mainstream imperative OO languages have for more than decade importing functional features at a mad clip, and why functional languages have historically either been impure (e.g., Lisp and ML and many of their descendants) or included embedded syntax sugar that supports expressing imperative sequences using more conventionally imperative idioms (e.g., Haskell do-notation.)

      The difference is that embedding functional idioms in imperative languages often requires warnings about what you can and cannot do safely to data without causing chaos, while imperative embeddings in functional code have no such problems.

    • And then you actually try to write it in a functional language, and end up with something like:

      cake = map (cool . bake 30 175) . splitIntoPans $ mix [ butter, sugar, walnuts ]

      6 replies →

    • If you want to bake a cake, FP like this could seem awkward.

      But what if you want to run a bakery and split the work across multiple cooks? In that case it helps to have clearly defined ingredients.

      I'm only trying to say that it all depends on the context. Obviously personal preference is a big factor too.

    • Baking a cake is like being a compiler and a processor for recipe instructions. Of course it seems awkward from the perspective of a human baker because before you can process/bake you have to "compile" the expression to procedural steps. The computer does that without complaint.

      This may illustrate that humans aren't good compilers of functional code, or in particular that humans aren't good at parsing poorly formatted functional code (again, computer parsers don't care about formatting). But I don't think it indicates that functional code isn't good for reading and writing, even for the same humans.

      I also don't think this recipe resembles FP. Where are the functions and their arguments? There is no visible hieararchy. It is unnecessarily obtuse in the first place.

    • > In any case the point is this: I had some straight imperative code that was doing the same thing several times. In order to make it generic I couldn’t just introduce a loop around the repeated code, but I had to completely change the control flow. There is too much puzzle solving here. In fact I didn’t solve this the first time I tried. In my first attempt I ended up with something far too complicated and then just left the code in the original form. Only after coming back to the problem a few days later did I come up with the simple solution above.

      There are two kinds of people, I guess. To me, this description simply encapsulates the process of being a programmer. Boo hoo, you had to think a little bit and come back later to a hard problem in order to figure it out.

      I'm sorry, but that's literally how every profession which requires engineering skills plays out. And like other professions, after you solve a problem once you don't have to solve the problem again. It's solved. The next template Gabriel writes in that flavor will not take nearly as long.

      Seriously, all of these points he raises against FP are entirely contrived, and come across as the meaningless complaining of an uninspired programmer.

      4 replies →

    • Never seen that before, thanks! It's very funny.

      I can't write Lisp to save my life, but I know roughly how you're supposed to do it.

    • It's a good analogy! But it also shows that in FP you have to specify what is needed for what and what happens why. If you wrote that imperatively, you could include steps like "go outside, count clouds, return" or "place a metal bowl next to everything, put some cereals inside". And then never return to that bowl again, just leave it like that. The programmer wanted to use this bowl for something, but then forgot it was there.

      And then, when someone returns to that code, they have no idea that these steps are unnecessary and why each step was taken. (Or maybe they are necessary, because cloud counting ensures there is time for ingredients to permeate?). So probably these steps will be left and more mess and jungle will accumulate.

  • Even in maths, I find a solution in terms of the problem easier to understand than one in terms of the previous step.

    Even when the recursive form is a more natural representation, like arithmetic sequences: start at s, increase by d with each step:

      a(0) = s, a(n) = a(n-1)+d
    
      a(n) = s + n*d
    

    The analytical form seems simpler, neater, more "right" and more efficient to me - even though, if you want the whole sequence, the recursive form is more efficient (given tail-call optimisation).

    I suspect I'm just not smart enough.

    fp can be much shorter, and the execution model isn't actually hidden, just unfamiliar (and unintuitive and unnatural - for me). Consider: all suffixes of a list. In jq:

      while( length>0; .[1:] )

    • >I suspect I'm just not smart enough

      Nah, I have a PhD in math and I agree with you completely. Imperative is way better. And most mathematicians agree with me. You can see this by cracking open any actual math or logic journal and looking how they write pseudocode (yes, pseudocode: where things like performance don't matter one tiny little bit). You'll see they're almost entirely imperative. Sometimes they even use GOTO!

      3 replies →

    • Lately I’ve been thinking that a lot of code style debates center around an explicit versus implicit axis. Imperative is more explicit, and, in one sense, easier to see what’s going on since it lays everything out step by step. On the other hand, those same steps are a mix of essential steps (that deal with the problem being solved) and accidental steps (that deal with computer and code in order to get the job done.)

      It seems to me that OOP, Functional, and Relational programming models try to abstract away the accidental steps, but like all abstractions there are limitations.

      I suspect that once familiar with one of these models, imperative seems awfully tedious, however now the code is more obscure to those not well versed in the paradigm, thus we have a trade off between ease of use for many and optimal for some.

      2 replies →

    • This doesn't look to me like the difference between functional and imperative so much as the difference between recursion / iteration and map / list comprehension.

      4 replies →

  • In an old textbook I haven't been able to find again (browsing in another uni's library) regarding the Entscheidungsproblem I read that Church wrote to Turing, saying he thought the Turing Machine waa a more convincing/natural/intuitive representation of how mathematicians thought about algorithms than his own lambda calculus.

    Maybe he was just being modest, or like John McCarthy, just didn't see or believe its potential.

    Note that this was before computers or programming, and that there's no formal proof that a Turning machine can encode any computation - so its convincingness was important.

  • This is correct. Everyone I've met that insisted that functional programming is superior to imperative has been a big time math/CS nerd, the kind that goes to grad school and was confused when the iPad launched because hey it does nothing that a laptop doesn't already do!

    My experience doing functional programming is that hurt my brain, it just doesn't map as cleanly to how I think of things happening compared to imperative programming. It was just really painful to code in, and most of my classmates had the same opinion.

    • It’s mostly a matter of practice. I think that many people’s experience of functional programming is a (potentially poorly-taught) university course, during which there is not really enough time to really become comfortable with functional programming. Maybe it’s true that the learning curve is a bit (a lot?) steeper, though. But once you are comfortable with it, it’s not significantly more difficult than writing code in Java or Python. I also think that it’s worth learning even just for the sake of becoming a better programmer. It teaches you to think in a different way, which also translates to programming in imperative languages.

  • Personally my thinking changes from Turing Machine to more math like with each year I do functional programming

  • Lisp lost in a much more profound way recently, and it's very rare to see anyone mention it, especially on the Lisp side of the conversation.

    Over the last 10 years or so, we have come to the painful conclusion that mixing data and code is a very, very bad idea. It can't be done safely. We are putting functionality into processors and operating systems to expressly disallow this behavior.

    If that conclusion is true, then Lisp is broken by design. There is no fixing it. It likes conflating the two, which means it can't be trusted.

  • > Apart from my code, even most of my todos are simple step-by-step instructions to achieve something.

    > [...]

    > This could be why OOP/Imperative was often preferred over FP.

    Though this doesn't really explain why OOP is preferred over imperative (since the former doesn't really correspond to a set of step-by-step instructions).

    • The latest no-OOP imperative language with any kind of market share is C. So everything that's terrible about C: unsafe manual memory, portability issues, tooling, no generics or overloading, horrible ergonomics, 2nd class functions, globals everywhere, etc, are all forever associated with imperative programming. OOP was born at the time of fixing all those problems, so those languages were a big improvement in ways that had nothing to do with OOP. Now that all the top languages are multi-paradigm, only a puritan would avoid OOP, and they'd have a tough time interacting with libraries and frameworks. So every codebase is a little wishy-washy and OOP wins by default. Imperative has no advocates left in industry or academia, so most people don't even think of it as a defensible design decision.

  • One language that was not on the presenters list is SQL, very popular, but not OO nor functional.

    One thing lot of programmers do is to abstract SQL to OO style, even though SQL describes a relation that can be computed to a result, in some way similar to a function, but it seems that most prefer to look at is has a state, even though it doesn't.

    Sure, the tables where data is stored has a state, but the sum of the tables is a relationship in time & depending how you look at it you get different results. It is very hard to map relationships to OO correctly.

    It is probably easier for most people to think about the world as set of things rater than a relation in time. Many of our natural languages are organized around things.

OOP was designed to prioritize encapsulation at the expense of referential transparency. Functional programming was designed to prioritize referential transparency at the expense of encapsulation.

You cannot have referential transparency and encapsulation at the same time.

In order to prevent mutations (which is a requirement of FP), a module cannot hold any state internally; this necessarily means that the state must be passed to each module action from the outside. If state has to be passed to each module action from the outside, then this necessarily means that the outside logic needs to be aware of which state is associated with which action of which child module. If higher level modules need to be aware of all the relationships between the logic and state of all lower level (child) modules, that is called 'leaky abstraction' and is a clear violation of encapsulation.

Encapsulation (AKA 'blackboxing') is a very important concept in software development. Large complex programs need to have replaceable parts and this requires encapsulation. The goal is to minimize the complexity of the contact areas between different components; the simpler the contact areas, the more interchangeable the components will be. It's like Lego blocks; all the different shapes connect to each other using the same simple interface; this gives you maximum composability.

Real world software applications need to manage and process complex state and the best way to achieve this is by dividing the state into simple fragments and allowing each fragment to be collocated with the logic that is responsible for mutating it.

If you design your programs such that your modules have clear separation of concerns, then figuring out which module is responsible for which state should be a trivial matter.

  • Encapsulation is desirable because it limits the possibility space of what can operate on a set of data. Referential transparency is desirable because pure programs are much easier to reason about. If I understand what youre saying, it seems youre saying referential transparency and encapsulation are at odds and encapsulation is more valuable, but I disagree. Hiding state maybe keeps things tidy and enforces that you need to use the API, but its not really the point IMO. The point of encapsulation is managing state mutations. Hiding state is only a small part. You dont need to hide state as much when its immutable because then you don’t need to care what other code is doing with your emitted data structures because it doesn’t effect you.

    • Encapsulation doesn't necessarily mean hiding state. It means hiding the implementation details of how actions mutate the state. The same action called on a different kind of module instance can end up mutating the instance's internal state in a completely different way. The higher level logic should not be concerned with how a module performs an action.

  • I don't quite follow this. You can create (very complicated) immutable objects that encapsulate their state, and provide methods that return new immutable objects with different - and still fully encapsulated - state. Vavr is a good example.

    • Yes you can reduce and map a large state object into a smaller and simpler object before you pass it down to a child component but the encapsulation is still leaky because the parent component needs to know the implementation details of each action of a child component in order to use them correctly (for example, the parent component needs to know how the different actions of the child relate to each other in terms of how they affect the state); it creates a large contact area between components which creates tight coupling.

      The idea of blackboxing/encapsulation is that the parent component should know as little as possible about the implementation of its child components.

      2 replies →

  • " the more interchangeable the components will be. It's like Lego blocks; "

    This is precisely the reason why pure FP is prioritizing referential transparency. Even if objects are perfectly encapsulated, with enough complexity, because other objects will depend on that information, and because that information mutates and changes over time, this is bound to cause some errors.

    Compilers can't check program correctness because of the halting problem, so FP aims to give the programmer some patterns + laws to help better reason across this "higher" dimension of moving parts.

    • >> Even if objects are perfectly encapsulated, with enough complexity, because other objects will depend on that information, ...

      I would argue that when other objects from different parts of the code depend on the same state and there is no clear hierarchy or data flow direction between those objects, then that is going to cause problems regardless of whether the language is OOP or FP. The problems will manifest themselves in different ways but it will be messy and difficult to debug in either case (FP or OOP) because this is an architectural problem and not a programming problem. It will require a refactoring.

      OOP helps to reduce architectural problems like this because it encourages developers to break logic up into modules which have distinct, non-overlapping concerns.

  • In my view, the new hooks paradigm in React combines the best of both worlds in FP and OOP.

I think we need to get past the point of believing in some FP revolution in which enlightenment happens and people suddenly switch to Haskell, OCaml, Clojure, etc. FP is happening in a more evolutionary way with newer languages like Kotlin, Scala, F#, etc. taking ideas from Haskell, SML, and Lisp.

I'm not pretending to be the first to state this observation but I feel like it needs reinforcement here.

  • I think most of the growth of FP is coming from libraries and hybrid languages. Things like React and Redux and streams/linq style operations on data structures, or default immutability. I don’t think “pure” languages will ever really become dominant but a lot of the best ideas are being borrowed.

I do not pretend to be a particularly skilled programmer, but in my not so long career I have picked up a bunch of tools: a few algorithms here and there, some data structures, some programming techniques like encapsulation, late binding, higher order functions, pipelines, various form of polymorphism (dynamic, static, ad hoc, inheritance based, structural or whatever), some concurrency patterns (message passing, shared memory, whatever). I end up using whatever seems more appropriate to me for a specific problem depending on intuition, personal preference and experience.

Now, various subsets of the items above have been labeled with different names (functional, procedural, OOO, generic, whatever), but of course most of the time no two people can agree on which subset deserves which label.

I must not be the only one, because a lot (but not all) of very successful languages are not very opinionated and let people mix and match bits as needed.

I didn't listen to the video, but the title raises questions. What is functional programming? Nowadays, most languages are multi-paradigm, it's not so clear what is functional programming (or a functional programming language).

For instance, it's very common to have data types with mutable state in OCaml, or to use non-mutable data-structures, closures, higher-order functions in let say Python. I don't see such a clear dichotomy between functional/non-functional programming languages anymore.

Besides, there are other language "features" that I feel have more impact on the code I write. For instance, static/dynamic typing, asynchronous I/O vs actors vs threads, module systems.

I see functional programming more as a tool and a programming discipline, well-suited to solve some problems, rather than a paradigm that one should adhere no matter what.

  • The talk actually takes time to answer these questions.

    The title is also a bit clickbaity because the talk acknowledges that fp as a style is becoming common.

JavaScript isn't a functional language itself, but you can use a functional library like lodash/fp (https://github.com/lodash/lodash/wiki/FP-Guide) on top of it to get all that lovely functional goodness in your frontend and node code. Using lodash/fp has made my frontend state management code a lot nicer, and I'm really only just starting out with it.

  • You may want to consider Ramda.js instead: https://ramdajs.com/

    IMHO does a better job than Lodash, because:

    1. All functions are automatically curried.

    2. The order of parameters lends itself to composition.

    EDIT: 3. Transducers.

    • This. (No pun intended.) Lodash had its FP features bolted on as an afterthought, whereas Ramda was designed for it from the start.

    • I never understood the point of Ramda. It's like it's trying to replace the core functionality of JS with something that's completely orthogonal to what the language actually is, but it's just a bolted on library.

      I've worked on codebases where people ignore all built-in JS functions (like Array.map/filter) and write Ramda spaghetti instead with multiple nested pipes and lens and what not to show off their FP purism.

      Most of the time, you don't need any of this, it just makes the codebase unreadable, and hard for new people to join the project and be productive in a timely fashion.

      6 replies →

  • Personally, I think JS is a fine functional language. Like you say, it doesn't have a good FP style system library, but it doesn't have a good anything style system library ;-) My main complaint is that currying is awkward. One thing I have discovered, though, is that closures are relatively slow (that is, unoptimised) in most implementations. In several implementations, they can also leak memory in certain circumstances. There is a very old outstanding bug in V8 that gives a lot of details about this... unfortunately I'm not in a position at the moment to go spelunking for it (I wish I'd saved a link...)

    Anyway, I've done quite a few fairly large katas in JS using only an FP style of coding without any dependencies and I really enjoyed it.

    • Personally I find functional style awkward in js. Mostly because data is not immutable, there are no functional operators (composition, application etc.) and no algebraic data types + pattern matching.

      But most importantly, prototypal inheritance, in other words invoking the object's own methods as if they were pure functions is what really puts me off.

      3 replies →

  • The video explains how JavaScript started out as a Scheme-dialect (Lisp) but for marketing reasons they chose a more Java-like syntax and adopted Java into the name.

    • Javascript falls short of scheme in ways more substantial than java-like vs s-expression syntax. It also has one of the worst numerical towers ever put into a language (that being: "lmao everything is a float".) Also, "function-scope" is an abomination compared to proper lexical scoping.

      Edit: I forgot to also mention: weak typing was an awful idea.

  • There is excellent TypeScript lib called fp-ts

    • I love everything except the docs. The docs rarely show practical usage. Most functions are just type definitions. This is a MAJOR blocker to anyone that might not have a mathematical background. I find this issue quite a bit with the FP world though. The old joke, "as soon as you understand monads, you instantly become unable to explain them" sort of holds true here. How would I know what I should use? You just have to know.

      Just this morning, I had to resort to Stack Overflow for using an Either... a concept I thought I well understood. Turns out, the way I've done it in Scala might not be the norm.

      Many programmers coming to this library are coming from JavaScript, so expecting them to understand some (or many) of these things, might not be the right approach. The author has gone to some great lengths to blog about the foundations of FP... so this might help a bit. I just wish the docs were fleshed out with more examples. (the repo is open sources.... I could put up or shut up here)

Because it's not that useful.

There is an contest organized by the International Conference on Functional Programming: https://en.wikipedia.org/wiki/ICFP_Programming_Contest

It was more or less designed to show the superiority of functional programming languages. Yet in that contest C++ has done better than OCaml or Haskell...

The FP crowd seems to be more active doing advocacy than writing code. Yes, we know, there is that one trading company using OCaml. It's such a niche language that they have to pretty much maintain the toolchain and standard library themselves. Meanwhile, plenty of more successful companies use C++, C# or Java with no problem.

If you want to convince someone of the superiority of FP, write a real killer application. A new browser to compete with Chrome, a video game that can dethrone Skyrim or the Witcher 3. Maybe a DBMS that's even better than PostgreSQL? Basically: show, don't talk.

  • Just because you don't see it, doesn't mean it's not happening.

    - Have you ever heard about how Walmart handles Black Fridays?

    - Do you even know what's behind Apple's payment system?

    - You ever used Pandoc, Couchbase, Grammarly, CircleCI, Clubhouse.io, Pandora, Soundcloud, Spotify?

    - Have you ever asked a question - what is an app like WhatsApp that was sold for $19 Billion runs on?

    - or How Facebook fights spam, Cisco does malware detection or AT&T deals with abuse complains?

    - How Clojure is used at NASA or how Microsoft uses Haskell?

    Frankly, I don't even know what's there to debate about. Functional programming is already here and it's been used in the industry for quite awhile already and its usage growing in a quite steady pace. Almost every single programming language today has certain amount of FP idioms, either built-in or via libraries. So yeah, while you're sitting there, contemplating about if FP useful or not, people been building hundreds of awesome products.

    • I said: it's not _that_ useful. I did not say it's completely useless.

      Every large (or even small) company has people writing stuff in Perl, Bash, Haskell, Ruby, Rust, VBA, Scala, Lua or what not. I've been that guy, too.

      More often than not it is a distraction more than anything, and it ultimately ends up being rewritten in C++, Java or Python. I think there are some niches where it helps; OCaml has had some success with static analysis and proof assistants, or even with code generation projects like FFTW.

      1 reply →

  • > A new browser to compete with Chrome

    Firefox is written in Rust

    > a video game that can dethrone Skyrim or the Witcher 3.

    afaik latest "God Of War" is written in Rust

    > Maybe a DBMS that's even better than PostgreSQL?

    Datomic - Clojure, Mnesia, Riak, CouchDB - Erlang

    Yeah, I know that Rust is not FP lang, it's imperative, but it does adhere to FP principles.

    "it's not that useful"? Heh.

Because it is not the best solution for most computer problems.

Simple as that.

I am a functional and OOP programmer myself. I find functional way more elegant for modeling most mathematical problems, but OOP way better at modeling real life things with states.

OOP and states introduce lots of problems and complexity, but the solution is not removing states, or a series of complex mathematical entelechies.

In fact "removing states" is not really removing them. It is creating new objects with static states on it. It makes it super hard to model real life.

(dynamic)States exist in real life. Temperature, pressure, height, volume, brightness, weight...

There are programmers that understand programs as a religion, they only program in one system ans believe it is the best thing in the world and everybody should be forced to use it. I feels sorry for them and the people that depend on them.

The solution will be new paradigms that are neither OOP nor FP.

  • >(dynamic)States exist in real life. Temperature, pressure, height, volume, brightness, weight...

    It's more like, states better match our more common way to model our sense-data. It's easier to grasp for us, but it doesn't mean it's the way that will cause provide the best desirable results.

    If you take the example of mass in physic, most of the time it's perfectly fine to deal with it as an first class attribute of an object. But it's not how Higgs mechanism aboard the notion.

  • Having used FP for the past decades in many different domains that's huge news to me.

One thing I haven't seen brought up in this thread yet is support for foreign language embeddability. For example, Python code is technically quite slow, but that often doesn't matter much because it is easy to write external functions in C or C++ that behave like normal Python functions. I imagine that it would be more difficult to embed C++ code into a language with strong functional gauruntees. In that sense, the performance of Python is close to the performance of the fastest language with the same paradigm, which is (with current compilers) better for imperative programs that are structurally more similar to how the CPU operates.

Good ideas take a long time to catch on in tech, regardless of how much anyone believes its a fast moving industry.

Functional programming? absolutely 100% yes.

Functional programming languages? well, it depends on the problem.

If performance is an important issue, most of the time functional programming languages are a big 'no'.

  • Well, if performance is really an issue, I guess anything that is not C, C++, rust or a thin wrapper over those languages or legacy libs written in the likes of Fortran won't be an option, so yes.

    That being said, it seems like performance is not an issue for most of the code written these days, aside from not writing quadratic solutions for problems solvable in linear time.

    If you use java, .net, go or the likes, odds are you would be fine with a functional language ; and if you need performance with those languages, odds are that you will need arcane knowledge equivalent to what you would need to know to make performant fp code.

  • I mean, Jane Street use OCaml for high-frequency trading, where latency can cost significant amounts of money. They seem to be perfectly happy with it.

This video exists in an alternate reality where marketing departments do not. Many of these languages became popular not because of some intrinsic property, but because of a strong marketing push by one or more backing companies. There was a period of time, not so long ago, where "object oriented" was basically a checkbox on language marketing copy, and if your language didn't have it you would get scoffed at.

  • Did you actually even skimmed the video? It does speak about large cash injection on the marketing side.

  • Can you give contemporaneous examples? I'm curious if there are companies out there actively pushing their language/framework, as opposed to sort of passively posting/updating without marketing.

    • The lines between marketing and "passively posting" are very blurry, especially in the tech world. Is Linus T. marketing, when in a technical presentation about git he says "if you like SVN you might wanna leave"? Is Mozilla marketing, when they claim in technical blog posts that rust provides system language level performance while being safe?

OO is merely a style of laying out imperative code for the compiler to put into proper linear order.

End of the day there are instructions emitted in a linear fashion and other instructions running (OS?) can provide an execution context ("Hi process, here's your memory area with pretend addresses do you can think it's all yours, you go over there to Core-2 and run at Z priority.")

OO is not particularly easy to learn WRT FP, but it does have the contextual advantage of having been delivered on the back of FAST compiled languages like C++.

Java runs as fast as the big money thrown into it's VM can make it run. If the JVM were dog-slow, you would see lower adoption of it.

Ocaml as used by corps like Jane Street etc,is not directly for running application code from (or rather, the application in question does code generation.)

High level languages could be expected to adopt either code-generational or Cython-style approaches. (Chicken Scheme, for example)

C++ merely has the historical accident of bridging 2 generational worlds of computing, hence you can find C++ full-stack.

Anyone for doing DSP purely in Ruby with no C-libs?

It´s basically because of marketing, fads, hype but we also have to take into account that FP is probably ok for the Hacker News audience but way too complex for the average developer.

Most code is LOB apps and social media apps churned by software factories and internal IS/IT areas. In these kind of projects coding is a rite of passage before becoming a team leader or a project manager, so most devs won´t invest much in their coding skills. As a result the average code tends to be badly decomposed procedural code over a procedural-like class hierarchy and devs just follow the fads because this is what gets them jobs.

Adding FP to this formula could prove really wrong for those in charge of projects. Better to be conservative and use Java, C#, Python or even nodejs/JavaScript as they allow to churn the same procedural code of ever just in different clothes.

I got another question. Why don't those prophets leave intelligent people alone and let them use whatever tooling/approach they find appropriate for solving particular problem instead of heating the air trying to propagate/force whatever ideology they carry.

People at the places I work keep memeing links to blog posts along the lines of "OOP is dead. Functional programming is the new king".

Yet to see a single line of a functional language in production.

As other commenters have mentioned most decent modern lanuages are multi-paradigm.

I feel it's because functional programming is not a general application methodology. It excels at several idioms that we use as programmers but I feel it's something more specialized and niche then OO programming. I personally use OO as a base and iterate from there, using Functional idioms where is applicable. Some classes of programs can be described in its entirety in functional terms, but they're a small portion compared to the whole. Everything can be expressed in OO idiom, even if it's not the optimum way; I don't know if the same can be said of Functional. Would like to know more;

  • I've been working with FP for around a decade now, and anything you can express in OO can be expressed with FP just as easily and often in a much simpler and more easily maintainable fashion. I copresented a talk on how my team uses FP in our platform if you're interested in more details:

    https://www.youtube.com/watch?v=IekPZpfbdaI

  • > Everything can be expressed in OO idiom

    You know, at some point in history most scientists in Europe believed that the math can only be done using Roman numerals.

Do not try and make the computer functional. That's impossible. Instead, only realize the truth... THERE IS NO COMPUTER. Then you will see that it not the computer that is functional, it is yourself.

Hm, so, Feldman claims that it wasn't the OO that made C++ popular, but rather the other features added on top of it that C with Classes didn't have. But one of those features that C with Classes didn't have was virtual functions. Without that, it's not clear how OO C with Classes really is. This potentially undermines Feldman's argument, because he hasn't ruled out the possibility that virtual functions were one of the key factors in C++'s success.

These things are not all-or-nothing.

I have one compute device, the GPU, that I program with its language (eg GLSL, OpenCL).

I have another compute device, the CPU, that I program with its language (eg C, C++).

I have code to control these devices, that mostly handles scheduling and waiting on the results of these computations (as well as network traffic and user input), and I program that in a language that supports functional style (eg C#, TypeScript).

as someone who made my first SPA, using Elm & met the presenter once in NY. functional programming is elegant and nice. but practicality is another different matter. for it, to be the norm, it has to have 10x advantages over the status quo. on the frontend, part JS already offers some features of functional programming, with some imperative parts. On the backend, none of the functional languages you would want to use such as Ocaml match say the ecosystems of Python, Java, Node.js & .Net world.Hell even F# which is an excellent language, is treated like the bastard step son of Microsoft

  • Clojure & Clojurescript are very practical and pragmatic. I've been writing Javascript for quite long time, I have tried and used most *script languages: Coffescript, Typescript, Livescript, Gorillascript. I've looked into Elm, ReasonML and Purescript. Clojurescript today has is the most balanced one - it gives you real productivity boost, simple FFI, different bundling options, gradual typing and generative testing, code that is clean, concise and very easy to reason about. It is a shame people dismiss it for some dogmatic reasons even without given it a try.

  • I mean, on the backend functional programming usually really shines, since you're can implement your APIs using FP without needing to have any state (the FP will just be translating http requests into calls to stateful storage).

    E.g. at Facebook, the PHP code I write is usually highly functional.

Functional programming is not new, it has been around for many decades. The reason it didn't catch on is because it doesn't map very well to how our brain works. Human brains are object oriented, so OOP is very easy to grasp.

The real question is, why are people now taking a second look at functional programming. And the answer is Moore's law. Moore's law is coming to and end, and CPUs are not getting faster. Instead they are adding more and more cores. To take advantage of lots of cores you need concurrency. OOP is not very concurrency-friendly because objects have state, and to avoid corrupting state in a multi-threaded environment you need locks, and locks reduce concurrency. Functional programming doesn't have state, so you don't need locks, so you can get better concurrency.

  • That's utter rubbish. My team has been working with Clojure for close to a decade now. We regularly hire coop students from university, and none of them have ever had problems learning functional programming. It typically takes around a couple of weeks for a student to become productive and start writing useful code. The only people I've ever met who say that FP doesn't map to the way our brains work are people who're deeply invested in imperative style and never tried anything else.

    The reasons for the imperative style being dominant are largely historical. Back in the day we had single core machines with limited memory and very slow drives. Imperative style and mutability makes a lot of sense in this scenario. Today, the problem of squeezing out every last bit of performance from a single core is not the most interesting one. And we're naturally seeing more and more FP used in the wild because it's a better fit for modern problems.

  • > Human brains are object oriented, so OOP is very easy to grasp.

    Can I cite you on this? Because I have only ever seen this explained in Programming 101, where Java is the language they teach.

    I wonder where this sentiment comes from. I imagine it came from marketing.

    • Yeah I've gotta be honest the first few times I was taught OOP I couldn't quite grasp the purpose. I like it now for encapsulation of state, but generally I find it much easier to deal with records + pure functions as building blocks.

    • > Can I cite you on this?

      No, you can't. Because like the other commenter noted: "This is utter rubbish." It only looks easy to understand on the surface, but quickly becomes a mess. "spaghetti code" and "lasagna code" are the terms invented in OOP realm. Being said that - some advanced FP concepts can be pretty daunting to grasp as well.

      Saying that human brains are OOP or FP oriented is equivalent to saying that human brains wired to recognize patterns in music but not color, or something like that.

  • > Functional programming doesn't have state, so you don't need locks, so you can get better concurrency.

    This is not true.

    Many algorithms are intrinsically imperative (e.g., quicksort). You can represent it using some monads in Haskell to hide this, but in the end your code is still imperative; and if you want to parallelize it, you still have to think about synchronization.

It might be nice to some but man if you are not required to learn a dozen different paradigms to use it. It’s expensive (harder to teach) and not intuitive for a beginner.

Maybe Elm itself is a killer app, but certainly not elm-ui. I don't think Datomic is a killer app too. Its certainly not comparable to Rails/OSes at scale

  • Sorry, but I think you need to take another look at Datomic

    • Datomic is really neat but, for any system that operates at significant scale, I think the approximately-10-billion-datom capacity is probably too great a concern.

      For example: Stop&Shop has 415 stores, and

        365 days * 415 stores * 100 purchases per day * 50 datoms per purchase
      

      will fill up your system in 14 years without even spending datoms on inventory and the like. And that "100 purchases per day" could be low by a factor of 5 or 10 (I don't know).

      1 reply →

Part of Python's strength is in its ecosystem related to machine learning. That, and it is a popular language to teach to kids these days.

To this newbie, procedural is ===SO=== much easier to understand.

  • Actually it's the other way around. For someone who is not exposed to programming at all, it is much easier to pick up a language like Clojure. This is not merely my opinion - I have seen it multiple times, with different people.

    Julie Moronuki who never had any exposure to programming at all and has a degree in linguistics decided to learn Haskell as her first programming language, just as an experiment. Not only she did manage to learn Haskell and become an expert, she co-authored one of the best selling Haskell books. I remember her saying that after Haskell other (more traditional) languages looked extremely confusing and weird to her.

    • I only had experience of coding in Matlab in university, and started learning Clojure in my first job. It was very intuitive.

So, I DO believe that this earnest high-level programmer is very earnest, I just don't think that he is starting with a full deck of cards. The manner in which he quickly brings up "C" and it's "killer app" being systems programming, and then jumps into the Javascript morass, it sort of suggests that he should start with first principles on how computers function.

Computers are imperative devices. I don't think that a for-loop or a map function fundamentally impede understanding of this concept. I DO think that pretending that languages that run on top of Virtual Machines need to aknowledge their dependency heirarchy and stop attempting to "level/equalize" the languages in question. One would use C in order to write a VM like V8 that then could run your scripting language. The core of Autocad is surely C++ with some lower-level C (and possibly assembler) regardless of whichever scripting language has then been implemented inside of this codebase, again, on a virtual machine.

The Operating System is a virtual machine. The memory management subsystem is a virtual machine.

Javascript runs on browsers. (Or V8, but then that was originally the JS engine of a browser) and has inherent flaws (lack of type system, for one) that limit it's use in specifying/driving code generation that could provide lower level functionality. THAT is the essential issue. VHDL and Verilog can specify digital logic up to a certain level of abstraction. C++ and C code generation frameworks can be used to generate HDL code to some degree, to the degree that libraries make them aware of the lower-level constructs such HDL's work in. I have no doubt that Pythons MyHDL presents a very low learning curve in terms of having the Python interface, but then the developer needs to be aware of what sort of HDL MyHDL will output and how it will actually perform in synthesis and on a real FPGA.

We don't need MORE layers of opaque abstraction. People need to learn more about how computers work as abstraction doesn't obviate the need to know how the lower levels work in order to optimize ones higher level code.

I can provide specific examples regarding libraries that purport to provide a somewhat blackbox interface, but upon deeper examination DO, in fact, require intimate knowledge of what is inside.

Abstractions are imperfect human attempts to separate concerns and they are temporary and social membranes.

Now, having said all of this: If a person ran a Symbolics Lisp system, such a system was holistic and the higher-level Lisp programmer could drill down into anything in the system and modify it or see how it was made.

I digress... read the source code for any magical black boxes you are thinking of employing in your work.

  • Some of those sources are pretty daunting...

    • indeed... hence the desire for blackboxes.

      leaky abstractions require the occasional lid-lifting... and all abstractions have a tendency to leak somewhere or other, especially if they attempt to be all encompassing.

      I think FP is certainly a viable high-level specification but ultimately there is lower-level code 'getting stuff done' (lol, "side effects") One has to be at least roughly aware of HOW ones specification is getting implemented in order to solve problems that arise and in order to optimize.

      This is all the more compelling reason to cease this relentless push to "cram more stuff down the tubes" or "add more layers to the stack"

      I honestly think that we need to return to KIS/KISS (keeping it simple)

      SIMPLIFY and remove extraneous stuff that prevents one from having a total mental model of what is happening.

Because it is difficult and funding flows to workflows which treat software like brick laying.

‘cause software development is as far away from math as plumbing. there, don’t need to watch the video anymore.

I cannot watch the video as youtube is blocked at my office. But I can answer the premise.

OO is the norm because it is has immediate business value and is easier to teach to young people. Most programmers in the work place are produced from educational institutions. Educational institutions has competitive quantifiable

FP requires thinking in terms of calculus. This isn't hard, personally I find it much faster and easier. Thinking in calculus does require some maturity, and possibly some analytical experience, young students may not find comfortable.

---

This question can also be answered in terms of scale.

FP reinforces simplicity. Simplicity requires extra effort, often through refactoring, in order to scale or allow extension for future requirements. This is a mature approach that allows a clearer path forward during maintenance and enhancements, but it isn't free.

OO scales immediately with minimal effort. OO, particularly inheritance, strongly reinforces complexity, but scale is easily and immediately available. This is great until it isn't.