Depending how you look at it, you could argue that classical approach to SOLID's dependency inversion is an amalgamation of two separate concerns - dependency injection for ensuring that neither "higher" nor "lower" level depend on the other directly, plus a type system restricting what operations are available to both. There are so many ways to look at and reason about the problem of structuring programs that pretty much every year I discover a new perspective on an old thing that blows my mind.
Now my enlightening moment about dependency injection was this: it's literally as simple as passing an argument to a function. In a functional approach, you may be passing lots of values and closures expressing dependencies with surgical precision, in an object-oriented imperative approach you might pass an instance conforming to an interface just once. But it's the same concept.
Now my enlightening moment about dependency injection was this: it's literally as simple as passing an argument to a function. In a functional approach, you may be passing lots of values and closures expressing dependencies with surgical precision, in an object-oriented imperative approach you might pass an instance conforming to an interface just once. But it's the same concept.