C# – How to Transition from OOP Object Composition to FP Function Composition

cfunctional programmingfunctionshigher-order-functions

I have been working for a few weeks on a new web project and I am realizing that all I am doing is basically calculations and transformations on data, and that most of my classes do not contain any state and could perfectly be turned into static classes with static methods. Therefore I am thinking that this could be a nice opportunity to architect the application following the functional programming paradigm. I have first done some research on the Internet to read about the experiences of other people trying something similar and I found a nice blog entry with some interesting ideas.

However, I am wondering how I should deal with the situation where you have multiple levels of nested function calls. I will try to give a simple example to show what I mean, first in OOP and then in FP.

In OOP I usually try to create simple classes that build functionality on layers by using composition. Something like this:

public class ClassLevel1
{
    private readonly IClassLevel2 _objLevel2;

    public ClassLevel1(IClassLevel2 objLevel2)
    {
        _objLevel2 = objLevel2;
    }

    public int FuncLevel1(int param1, int param2)
    {
        // Some operations here
        var res = _objLevel2.FuncLevel2(param1) + param2;
        // Some more operations here with the 'res'
        return result;
    }  
}

public class ClassLevel2
{
    private readonly IClassLevel3 _objLevel3;

    public ClassLevel2(IClassLevel3 objLevel3)
    {
        _objLevel3 = objLevel3;
    }

    public int FuncLevel2(int param1)
    {
        // Some operations here
        var res = _objLevel3.FuncLevel3(param1);
        // Some more operations here with the 'res'
        return result;
    }  
}

Then I can rely on dependency injection to build the instances and I can take advantage of any mocking framework to very easily unit test each class.

Now let's imagine that I would like to move to FP and let's say that we have a function FuncLevel1 that internally calls FuncLevel2, which internally uses a third function FuncLevel3. One of my main goals would be to structure the code in such a way that I can easily mock each function in my unit tests. For example, the code would like this:

public static int FuncLevel1(
    Func<Func<int, int>, int, int> FuncLevel2,
    Func<int, int> FuncLevel3,
    int param1,
    int param2)
{
    // Some operations here
    var res = FuncLevel2(FuncLevel3, param1) + param2;
    // Some more operations here with 'res'
    return result;  
}

public static int FuncLevel2(
    Func<int, int> FuncLevel3,
    int param1)
{
    // Some operations here
    var res = FuncLevel3(param1);
    // Some more operations here with 'res'
    return result;  
}

Then function FuncLevel1 is called like:

var res = FuncLevel1(FuncLevel2, FuncLevel3, 5, 10);

The advantage of this structure is that I can mock the functions FuncLevel2 and FuncLevel3 if I want to unit test FuncLevel1 and FuncLevel2 respectively.

In a simple scenario I realize that you could write the code instead as:

var res3 = FuncLevel3(5);
var res2 = FuncLevel2(res3) + 10;
var res1 = FuncLevel1(res2);

But it is easy imagine that there may be other (more complex) situations where it is not possible to solve the problem like this.

In case you have deeply nested function calls, then passing all the required functions at the lower levels all the way from the top can produce some cumbersome code. Therefore I am very interested in reading about alternatives to better handle a scenario like this.

Best Answer

In a functional language like F#, you could take advantage of partial application. That is, FuncLevel1 only has one function parameter, FuncLevel2 and it already contains FuncLevel3 inside it:

let funcLevel1 (funcLevel2 : int -> int) (param1 : int) (param2 : int) : int =
    let result = funcLevel2 param1 + param2;
    result

let funcLevel2 (funcLevel3 : int -> int) (param1 : int) : int =
    let result = funcLevel3 param1
    result

Usage:

let result = funcLevel1 (funcLevel2 funcLevel3) 5 10

In C#, you could model the functions the same way too:

public static int FuncLevel1(
    Func<int, int> FuncLevel2,
    int param1,
    int param2)
{
    var result = FuncLevel2(param1) + param2;
    return result;  
}

The question is how to perform the partial application. C# does not support it directly, but you can emulate it using lambdas:

var res = FuncLevel1(i => FuncLevel2(FuncLevel3, i), 5, 10);

Another option would be to write a helper method that does the partial application:

public static Func<T2, T3> PApply<T1, T2, T3>(Func<T1, T2, T3> func, T1 arg1)
{
    return arg2 => func(arg1, arg2);
}

But when you try to use it:

var res = FuncLevel1(PApply(FuncLevel2, FuncLevel3), 5, 10);

you get a compile time error about not being able to infer type arguments. That error is fixable, but it results in worse code than the lambda version, so I would stick with that.

Related Topic