Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Today I've just seen this article which described the relevance of SOLID principle in F# development-

F# and Design principles – SOLID

And while addressing the last one - "Dependency inversion principle", the author said:

From a functional point of view, these containers and injection concepts can be solved with a simple higher order function, or hole-in-the-middle type pattern which are built right into the language.

But he didn't explain it further. So, my question is, how is the dependency inversion related to higher order functions?

share|improve this question
add comment

3 Answers

up vote 15 down vote accepted

Dependency Inversion in OOP means that you code against an interface which is then provided by an implementation in an object.

Languages that support higher language functions can often solve simple dependency inversion problems by passing behaviour as a function instead of an object which implements an interface in the OO-sense.

In such languages, the function's signature can become the interface and a function is passed in instead of a traditional object to provide the desired behaviour. The hole in the middle pattern is a good example for this.

It let's you achieve the same result with less code and more expressiveness, as you don't need to implement a whole class that conforms to an (OOP) interface to provide the desired behaviour for the caller. Instead, you can just pass a simple function definition. In short: Code is often easier to maintain, more expressive and more flexible when one uses higher order functions.

An example in C#

Traditional approach:

public IEnumerable<Customer> FilterCustomers(IFilter<Customer> filter, IEnumerable<Customers> customers)
{
    foreach(var customer in customers)
    {
        if(filter.Matches(customer))
        {
            yield return customer;
        }
    }
}

//now you've got to implement all these filters
class CustomerNameFilter : IFilter<Customer> /*...*/
class CustomerBirthdayFilter : IFilter<Customer> /*...*/

//the invocation looks like this
var filteredDataByName = FilterCustomers(new CustomerNameFilter("SomeName"), customers);
var filteredDataBybirthDay = FilterCustomers(new CustomerBirthdayFilter(SomeDate), customers);

With higher order functions:

public IEnumerable<Customer> FilterCustomers(Func<Customer, bool> filter, IEnumerable<Customers> customers)
{
    foreach(var customer in customers)
    {
        if(filter(customer))
        {
            yield return customer;
        }
    }
}

Now the implementation and invocation become less cumbersome. We don't need to supply an IFilter implementation anymore. We don't need to implement classes for the filters anymore.

var filteredDataByName = FilterCustomers(x => x.Name.Equals("CustomerName"), customers);
var filteredDataByBirthday = FilterCustomers(x => x.Birthday == SomeDateTime, customers);

Of course, this can already be done by LinQ in C#. I just used this example to illustrate that it's easier and more flexible to use higher order functions instead of objects which implement an interface.

share|improve this answer
    
A bit of example please? Or maybe link(s) for example. –  Gulshan Aug 25 '11 at 7:32
1  
Nice example. However, like Gulshan I'm trying to find out more about functional programming and I was wondering if this kind of "functional DI" doesn't sacrifice some rigor and significance compared to "object oriented DI". The higher order signature only states that the function passed must take a Customer as a parameter and return a bool whereas the OO version enforces the fact that the object passed is a filter (implements IFilter<Customer>). It also makes the notion of filter explicit, which could be a good thing if it is a core concept of the Domain (see DDD). What do you think ? –  guillaume31 Aug 25 '11 at 8:26
2  
@ian31: This is an interesting topic indeed! Anything that is passed to FilterCustomer will behave as some sort of filter implicitly. When the filter concept is an essential part of the domain and you need complex filter rules that are used multiple times accross the system, it's sure better to encapsulate them. If not or only to a very low degree, then I'd aim for technical simplicity and pragmatism. –  Falcon Aug 25 '11 at 8:37
2  
@ian31: I completely disagree. Implementing IFilter<Customer> is no enforcement at all. The higher-order function is vastly more flexible, which is a big benefit, and being able to write them inline is another huge benefit. Lambdas are also much easier able to capture local variables. –  DeadMG Aug 25 '11 at 11:53
1  
@DeadMG: You're looking at it from a technical perspective. From that point of view, I concur. But ian31 is looking at it from a DDD perspective. The concrete filters add value to an ubiqitous language when they're a core concept of the domain model. Also they can help enforcing the DRY principle. –  Falcon Aug 25 '11 at 11:57
show 6 more comments

If you want to change the behaviour of a function

doThis(Foo)

you could pass another function

doThisWith(Foo, anotherFunction)

which implements the behaviour you want to be different.

"doThisWith" is a higher-order function because it takes another function as an argument.

For example you could have

storeValues(Foo, writeToDatabase)
storeValues(Foo, imitateDatabase)
share|improve this answer
add comment

Short Answer:

Classical Dependency Injection/Inversion of Control uses a class interfaces as placeholder for dependant functionality. This interface is implemented by a class.

Instead of Interface/ClassImplementation many dependencies can be easier implemented with a delegate function.

You find an example for both in c# at ioc-factory-pros-and-contras-for-interface-versus-delegates.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.