| > For the entire app? You'd end up with a "god object" that would make the app unmaintainable. OO gives you compartmentalization that you don't get with FP. Well, not quite; take a look at the Elm architecture [0]. It's basically what Redux gives you, but more explicit. The idea is, that yes, while you have a god object in the top-most component, child components don't know anything about it; they operate on their piece of state completely independently. This makes UI elements perfectly composable and reusable, since in the end, a UI element is just a pure function and nothing more. Not to mention other nice side-effects (sorry :)) of pure UI architectures, like time-travelling debugging, sane logging and so on. > FP is great for problems up to a certain complexity. After that it falls apart. I disagree completely. FP, and moreover pure FP, is especially well suited for complex problems. Pure functions are testable (if you haven't heard of QuickCheck / generative testing, you've missed out) and as I said above, composable. If anything, I've never seen a big OO program made out of truly reusable components. Because classes and methods are often impure, before calling a method one must make sure that the correct environment is set up in the right way (if you've ever forgotten calling initSubsystem() before subsytemDoSomething() you know what I mean). One can rip out a pure function from one codebase and reuse it, as-is, no modification necessary, in another one without any problems. How often does this happen in a big OO project? > Is "instance" adding an interface to TileMap/HexMap so that either can be passed in as a parameter that requires a RectIterable? Can other interfaces be added that way to TileMap/HexMap? Yes, and yes. In Java, when you have a class like this: class A implements B, C {
...
}
in some library, you can't add D to the list of implemented interfaces.In Haskell, you can: instance D A where
...
Haskell assumes an "open world" - i.e. everybody can add instances to a data type even after it has been defined already.I can't give you a complete overview of the differences between ad-hoc and parametric polymorphism, but there are plenty of resources online if you are interested. > In my editor, can I say something like myTileMap.iterateRect after doing this, or do I need to know that iterateRect exists and remember exactly what it's called? I can only speak for Haskell here. It's a static language, so things like autocompletion, show type at cursor, jump to definition etc are not a problem. The tooling could be a whole lot better, no doubt, but it's not bad. The REPL helps a lot, too. [0] https://guide.elm-lang.org/architecture/ |
TypeScript, which is my current OO language, will use signatures to match to an interface, so it's even more open: You can create an object with the right members and pass it in to a function expecting an interface without even explicitly identifying it as "implementing" the interface.
> If anything, I've never seen a big OO program made out of truly reusable components.
Agreed. The point of using OO in a giant complex program isn't just the reuse, which you point out is exaggerated. The point of using OO in a giant complex program is the isolation you get, so that a team of 1000 people can develop the app in a reasonable way.
I think the cost of FP as the complexity of a program goes up is that the cognitive load to think about the structure of the program goes up exponentially faster than OO. Debugging is a huge issue when things get complicated, and the last I heard Haskell debugging is still in its infancy. A debugger where you just can step through the code is really, really important for some kinds of analysis.
It's all Turing Complete, so you can do anything in FP that you can do in OO. It just feels harder to decompose problems into FP units than OO units, at least at a larger architectural level. Not everything is easily isolated: Sometimes you need a control over here to poke into the state of a control over there, and you don't want that information in some "god object" at the top level; you want a direct connection and mutability.
I have heard good things about Elm, and will probably give it a try at some point. But my 30+ years of programming experience have given me a (possibly incorrect) strong intuition that FP just won't work well for some problems. Can they apply to them? Sure.
> [...] pure FP, is especially well suited for complex problems.
Which is why it's so popular for solving complex problems? Looking at a list of Haskell's uses in industry [1] and applications [2] I don't see a single example of Haskell used in what I would call a "complex problem". Lots of machine learning, parsing/compiling, and transformation tools. Some games written by amateur game developers -- getting a game working is about 10% of the problem. A very few more complex apps that I've never heard of, but nothing that hits the complexity of even a Microsoft Word or Adobe Photoshop, much less a 3d editor like Maya. There's an order of magnitude more complexity in an app like those.
Haskell is 27 years old. Over the last ten years it's been incredibly popular. Totally enough time for at least a few high profile applications to have been created. Where are they?
Maybe Haskell would be a better platform, but it's just harder for many programmers to think pure-FP. But even that's a real limitation: If you're putting more cognitive load on the developer, then you're just changing the problems, not preventing them.
[1] https://wiki.haskell.org/Haskell_in_industry
[2] https://wiki.haskell.org/Libraries_and_tools