5

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.

  • Tell me what is the problem again? Just say it in 15 words or less (it's the reason your post title is terrible). Start with the 3 words "How do I" or "How can I". – Robert Harvey Jun 23 '16 at 19:40
  • Have a look at extension methods. Extension methods are a great way to tame some of this complexity. – Robert Harvey Jun 23 '16 at 19:43
  • 1
    Naming temporary results to make an expression more maintainable is perfectly okay. Just don't reuse the variable. Interesting things start when you don't know how the functions you pass are combined by FuncLevel1, and cannot just reproduce it locally. – 9000 Jun 23 '16 at 19:44
  • 1
    Consider whether you need your function to vary so much. If you are always going to call FuncLevel1 with FuncLevel2 and FuncLevel3, there's no need to have them as parameters. – Andrew Piliser Jun 23 '16 at 22:06
  • 1
    @CarlosRodriguez You might want to explain why you need to mock the functions in unit tests. If you are unit testing at the level of individual functions, you may be over-engineering the testing code. – Frank Hileman Jun 24 '16 at 16:50
0

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.

  • Thank you for the answer. Using lambdas to emulate partial application is a good idea, but I wonder how would that scale if you deeply nested functions. Don't you think code will become unmanageable? Do you have any suggestions? I realize that maybe you shouldn't write your application in such a way, but I am just trying to take this idea to the limit. :-) – Carlos Rodriguez Jun 29 '16 at 11:45
  • @CarlosRodriguez You would have to measure, but I imagine it could become a problem in code that's very performance sensitive. You could probably create a custom delegate-like type that is optimized for efficient PApply to work around that. – svick Jun 29 '16 at 12:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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