3 ms·
The benefits you describe for OOP can be achieved in FP through function composition. DI doesn't have to mean you set up a container, you know. > I know that s
by etripe 6y ago
The benefits you describe for OOP can be achieved in FP through function composition. DI doesn't have to mean you set up a container, you know.
> I know that something akin to this is theoretically possible in functional languages, but I've found that in practice it's more difficult.
Could you explain what you think is hard about it?
- chriswarbo 6y agoFunction composition doesn't spring to mind when I think fakes/mocks/testing. As a long-time functional programmer, the things I'd reach for are: Higher-order functions: rather than taking a 'service object' as an argument, and calling one or two of its methods, we can accept the methods/functions we need as arguments. Tests can pass in their own functions, which looks a lot like mocking but doesn't need any tricks or frameworks. This is the easiest approach for simple cases, but incurs lots of boilerplate as it's used more and more. Records: these are name/value collections (think '{foo: bar, ...}' in JS). Since the values can be functions, they're pretty much objects; but we can swap out these values without having to define classes, etc. We can use these just like 'service objects' in OOP. Type classes/interfaces: these define certain operations/methods that can be performed on a given type, even if that type's generic. They're essentially records like above, but chosen by the compiler based on the type; some languages (e.g. Agda, Idris, Scala) also allow overrides to be taken from the current scope. Domain-specific languages: we treat the methods/operations of our API as if they're builtin-functionality of some 'embedded' language. When we use such functionality, the result is a program for that embedded language. We can run these programs by defining an "interpreter" (a function which implements each of these operations); we can define a 'real' interpreter and a test interpreter. This is the most hardcore, and usually benefits from some framework for doing the necessary plumbing. I wouldn't recommend it as a first step, but I've had success doing this with Haskell's Polysemy library; another popular library is Haskell's 'Monad Transformer Library' but I've not used that myself.
- etripe 6y agoI'm relatively new to FP, so maybe I'm getting my terminology wires crossed. Perhaps instead of function composition I should have said currying and you would have gotten my drift. That is what you seem to be saying in your second paragraph.