| > when I hear "mock object" it's time to run Do Haskell programmers not create mocks to test external components? > OOP is the wrong-minded idea that a program should be a bundle of many "self-contained" objects. But that's wrong, we're writing ONE program here, not thousands. The number of programs isn't the relevant metric. Complexity is. Any complex system is going to trend toward modularity. Modularity requires standard interfaces, which inevitably lead to bureaucracy. A 1MM line Haskell program is going to be similarly bureaucratic. There are going to be standards you have to adhere to in order to play nice with the rest of the system. That's what typeclasses are, after all. OOP is traditionally defined by three things: polymorphism, encapsulation, and inheritance. Polymorphism: Modern Non-OOP languages can also be polymorphic, so that's no longer a differentiator. Encapsulation: You definitely want encapsulation if your data is mutable. Inheritance: This is the only truly problematic feature, and it's certainly abused, but it has its place. I don't always want to compose and delegate 20 methods when I just want to change the behavior of one. |
Haskell had ad-hoc polymorphism way before Java was a twinkle in its creator's eye. Before Haskell, Miranda (the language Haskell was based off of) could have kicked Java's polymorphism to the curb. Neither Java nor OOP invented polymorphism. If anything, they butchered it by introducing subtyping.
> Do Haskell programmers not create mocks to test external components?
The equivalent in Haskell would be having some kind of 'effects' system. An effect system differs from a mock object in that it limits in its totality what kind of interactions can take place. Typically, each layered effect also has a set of laws. Pure interpreters can be written for these effects, but the impure (i.e., real-world) interpreters are not privileged in their consumption of this effect. The pure interpreter also provides a proper implementation, such that you should be able to replace your real program with all pure interpreters, supply all your input at once, and still have a correct program. In other words, a Haskell program is typically polymorphic over which effects it uses in a way that other languages simply aren't.
> Encapsulation: You definitely want encapsulation if your data is mutable.
Again, Haskell, Miranda, and Lisp had encapsulation long before OOP came about, and Lisp has mutable data.