Currying vs Dependency Injection

itbhp

Paolo Sciarra

Posted on December 29, 2023

Currying vs Dependency Injection

In this article, I want to describe a very simple concept used in functional programming: currying.

We have to imagine that in most functional languages, we deal mainly with functions. I will use Java as language for my examples, but it should be fairly easy to understand them and adapt to your language of choice.

Let's analyse the type of few functions:

public interface ExampleFunctions {
 Integer invertSign(Integer input);
 Integer add(Integer a, Integer b);
 Command createFrom(Properties ps, Pattern p, CommandFactory f);
}
Enter fullscreen mode Exit fullscreen mode

Here we can see we have:

  1. invertSign that has type: Function<Integer, Integer>
  2. add that has type: Function<Integer, Integer, Integer>
  3. createFrom that has type: Function<Properties, Pattern, CommandFactory, Command>

For non Java programmers, the interface Function in Java is generic or parameterised and the first n parameters represent the function inputs or arguments, and the last is the return type.

Now let's focus our attention on the two functions that have more than one argument add and createFrom.

Suppose you want to create an adder object, that adds any integer to a given number, like a fiveAdder.

Using an object oriented style, you can write a class like:

public class Adder {
 private final Integer firstAddend;

 public Adder(Integer firstAddend){
  this.firstAddend = firstAddend;
 }

 public Integer add(Integer number){
   return firstAddend + number;
 }
}
Enter fullscreen mode Exit fullscreen mode

In this class we require a firstAddend integer dependency in the constructor, and then we have a different add method that takes just one parameter.

This way of passing parameters to an object is called Dependency Injection in this case through a constructor.

Using the concept of currying, we could have done this without declaring any class.

Currying is the transformation of a function that takes a structure of n arguments, into a chain of functions each taking one argument.

So for functions that take two arguments, we can write a curry function like this:

Function<A, Function<B, C>> curry(Function<A, B, C> f);
Enter fullscreen mode Exit fullscreen mode

Then using this function we could have written:

var fiveAdder = curry(ExampleFunctions::add).apply(5);
Enter fullscreen mode Exit fullscreen mode

Just like that, we have a function that adds any integer to five.

Now take for example the other function createFrom.

Imagine a situation where you have different Command objects, like TurnOnCommand and TurnOffCommand, and you want to use that method to create them in different ways (using different patterns, and different constructors), but for all of them, you want to use the same Properties object.

We can leverage the currying concept for functions with 3 arguments:

Function<A, Function<B, Function<C, D>>> curry(Function<A, B, C,D> f);
Enter fullscreen mode Exit fullscreen mode

And then write:

var someProperties = ...;
var factory = curry(ExampleFunctions::createFrom).apply(someProperties);
var turnOnFactory = factory.apply(turnOnPattern).apply(TurnOnCommand::new);
var turnOffFactory = factory.apply(turnOffPattern).apply(TurnOffCommand::new);
Enter fullscreen mode Exit fullscreen mode

There you have a factory function variable created after applying the first argument, someProperties, to the curried version of the createFrom method.

Without using currying you could have written:

var someProperties = ...;
var turnOnFactory = createFrom(someProperties, turnOnPattern, TurnOnCommand::new);
var turnOffFactory = createFrom(someProperties, turnOffPattern,TurnOffCommand::new);
Enter fullscreen mode Exit fullscreen mode

or using dependency injection:

public class CommandsFactory{
  private final Properties p;

  public CommandsFactory(Properties p){
    this.p = p;
  }

  public Command createFrom(Pattern p, CommandFactory f){
   ...
  }
}
Enter fullscreen mode Exit fullscreen mode

I hope you now have clear what currying means, and how you can use it as a replacement for new class creation and dependency injection, or how somehow these concepts are related.

💖 💪 🙅 🚩
itbhp
Paolo Sciarra

Posted on December 29, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Currying vs Dependency Injection
java Currying vs Dependency Injection

December 29, 2023