Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The only thing I don't like is the DI story presented here and many other F# guides. Having gone down that rabbit hole and using F# in production for 5 years now, I have gone back to classes and interfaces in almost all cases.

Functions as DI mechanism suffers from a few things. First, it's hard to search for implementations. They could be defined anywhere. With interfaces, the implementations are a hot key away. Second, functions only replace single-function interfaces. Even with a purist view of ISP, there are still plenty of occasions where a service would expect to call multiple functions on a contained service. Passing all those in as multiple parameters gets unwieldy in real world scenarios. Third, F# has no way to inject a dependency into a whole module, so you have to go function by function. Injection into classes is much easier to manage this way. Finally since none of the services or interfaces are named, they don't work with IoC containers.

The good side is that there is nothing in F# preventing you from using classes and interfaces in your design. Unsurprisingly this is my preferred way to go about it.

I kinda wish the function based DI wasn't brought up so much and so early. It's a big mental leap that I think turns off some people coming from other languages. And for limited benefit. Or negative benefit in plenty of cases.



I use classes and interfaces at component boundaries, which is encouraged by the FSharp style guide https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/, and use just functions for DI internally where it makes sense.


I believe this class-oriented workaround is a side-effect of Don Syme's decision to strip out the OCaml module system from F#.


Can the F# compiler not convert a lambda to a single-function interface instance? Honest question. I'm mostly a Java guy, and I know that is how Java works under the hood because the JVM does not have the concept of delegates. But it seems like a fairly simple and safe transformation, even when your underlying target does have delegates.


No, while implementing such a feature wouldn't be difficult, one of F#'s imperatives is to ensure type conversions are explicit everywhere. Plus, given dotnet does have delegates, and F# has anonymous classes that would give a one-line workaround, this feature would be of limited use.


It sounds like your (more or less) just using classes for just namespacing functions and allowing bundles of functions to get brought in?


I've definitely structured f# modules that way. The module exposes one function that "injects" the dependency into multiple other functions, and then returns them as a blob.

I'm not sure if that's "the fsharp way" (i suspect it isn't) and maybe I'll look back on it some day and cringe, but it's working pretty well for some of my (admittedly small) side projects I'm tinkering with right now.


Yes, that's what I do too. "Service" modules contain all the functions, with all dependencies explicitly passed into them, and at the bottom of the module is an interface with the dependencies assumed injected and a factory function that takes all the dependencies and returns an object with that interface.

In general I use a suave functional styled api on the top, OO-style SOA in the middle, and mostly functional style at the bottom layer, something of an FP-OOP-FP sandwich. I jokingly call it sandwich oriented programming.


Not the OP but IME with a lot of web/api development work this seems to be the case more than not.

I do realize that most web work is really more functional than OOP, but classes do make it very easy to bundle dependencies without adding noise to the implementation/signatures.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: