Pierre-Yves Saumont has managed his own company for 15 years, specializing in natural language processing. At the same time, he has been the publishing manager for the French subsidiary of a leading American computer books publisher. He wrote about 30 books about computers and software development in Java. Since 2008, he works for Alcatel-Lucent Submarine Networks as an R&D Software engineer, and he is responsible for the architecture of several projects such as distributed application framework, functional framework and functional DSML (Domain Specific Modeling Language). He is also a double bass Jazz player. Pierre-yves has posted 7 posts at DZone. You can read more from them at their website. View Full User Profile

What's Wrong with Java 8: Currying vs Closures

04.19.2014
| 32999 views |
  • submit to reddit
There are many false ideas around about Java 8. Among these is the idea that Java 8 brings closures to Java. This is wrong. Closures have existed in Java since the beginning. But closures are evil. And while Java 8 seems to go toward functional programming, Java closures should be avoided as much as possible. But Java 8 does not help us very much in this area.

One huge difference between using a method and using a function is parameter evaluation time. In Java, one can write a method taking some arguments and returning a value. Is this a function? Not at all. A method can't be manipulated in any other way than calling it, and this implies that its arguments will be evaluated before the method is executed. This is a consequence of arguments being passed by value in Java.

Functions are different. One may manipulate functions without evaluating them. And one has complete control over when the arguments are evaluated. And if a function has several arguments, they may be evaluated at different time. This may be done through the use of currying. But first, we will see how this may be done with closures.

Examples of closures

A closure is the fact, for a function, to be able to access something in the enclosing context. In functional programming, the result of a function should only depend upon its arguments. Closures clearly break this rule.

Let's see an example in Java 5/6/7:

private Integer b = 2;

List list = Arrays.asList(1, 2, 3, 4, 5);

System.out.println(calculate(list.stream(), 3).collect(toList()));

private Stream calculate(Stream stream, Integer a) {
  return stream.map(new Function() {

    @Override
    public Integer apply(Integer t) {
      return t * a + b;
    }
  });
}

public interface Function<T, U> {
  U apply(T t);
}

This code will produce the following result:

[5, 8, 11, 14, 17]

which is the mapping of the function f(x) = x * 3 + 2 on the list [1, 2, 3, 4, 5]. So far, so good. But wait..., could 3 and 2 be replaced with some other values? In other words, isn't it rather the mapping for function f(x, a, b) = x * a + b onto the list?

Well, yes and no. No, because a and b are implicitly final, so they act as constants at the time the function is evaluated. But sure, they may vary. The fact that they are final (implicitly in Java 8, explicitly in previous versions) is only a way for the compiler to optimize compilation. The compiler does not care at all about the potentially changing values. What it cares about is that the references do not change. In other word, it wants the reference to the Integer objects a and b not to change, but it does not care about the values. This appears in the following version:

private Integer b = 2;

private Integer getB() {
  return this.b;
}

List list = Arrays.asList(1, 2, 3, 4, 5);

System.out.println(calculator.calculate(list.stream(), new Int(3)).collect(toList()));

private Stream<Integer> calculate00(Stream<Integer> stream, final Int a) {
  return stream.map(new Function<Integer, Integer>() {

    @Override
    public Integer apply(Integer t) {
      return t * a.value + getB();
    }
  });
}
-
static private class Int {
  public int value;

  public Int(int value) {
    this.value = value;
  }
 }

Here, we use a mutable object for a (of class Int instead of Integer, which is immutable), and a method to access b. We now simulate a function of three variables, but we still use a function of one variable and two closures to replace the two other variables. This is clearly non functional, because it breaks the rule about depending only upon the function's arguments.

One consequence is that we may not reuse the function somewhere else, should we need to, since it depends upon the context and not only upon its argument(s). We will have to duplicate the code. Another consequence is that we can't test our function in isolation, since we need the context to make it work.

So, should we use a function of three arguments? We may think that this is not possible. The reason for this is related to where arguments are being evaluated. All three arguments are being evaluated in different places. If we were using a function of three arguments, they would have to be evaluated at the same time. This is not possible since the map method will map a function of one argument to the stream, not a function of three arguments. So, the two other arguments must have been already evaluated when the function is binded (passed to map). The solution is to evaluate the other two arguments first.

We get this effect with closures, but this results in non testable code and potential duplication.

Using Java 8 syntax (lambdas) will not change anything to this:

private Integer b = 2;

private Stream<Integer> calculate(Stream<Integer> stream, Integer a) {
  return stream.map(t -> t * a + b);
}

What we need is a way to apply all three arguments at different times. This is called currying (despite the fact that it was invented by Moses Shönfinkel!).

Using currying

Currying is the fact of evaluating function arguments one by one, producing a new function with one argument less on each step. For example, if we have the following function:

f(x, y, z) = x * y + z

we may apply the arguments 2, 4, 5 at the same time and get:

f(3, 4, 5) = 3 * 4 + 5 = 17

But we may also apply only 3 and get:

f(3, y, z) = g(y, z) = 3 * y + z

We have now a new function g, taking only two arguments. We can curry again this function, applying 4 to y:

g(4, z) = h(z) = 3 * 4 + z

The order in which we apply the arguments is irrelevant. We are not performing partial calculation. (We would have to respect operators precedence). We are performing partial application of the function.

How can we do this is Java? Here is what we can do in Java 5/6/7:

private static List<Integer> calculate(List<Integer> list, Integer a) {
  return list.map(new Function<Integer, Function<Integer, Function<Integer, Integer>>>() {

    @Override
    public Function<Integer, Function<Integer, Integer>> apply(final Integer x) {
      return new Function<Integer, Function<Integer, Integer>>() {

        @Override
        public Function<Integer, Integer> apply(final Integer y) {
          return new Function<Integer, Integer>() {

            @Override
            public Integer apply(Integer t) {
              return x + y * t;
            }
          };
        }
      };
    }
  }.apply(b).apply(a));
}

This definitely does the Job, but I guess it will be difficult to convince developers that they should code using this style! Hopefully, the lambda syntax of Java 8 will help us:

private Stream<Integer> calculate(Stream<Integer> stream, Integer a) {
  return stream.map(((Function<Integer, Function<Integer, Function<Integer, Integer>>>)
                       x -> y -> t -> x + y * t).apply(b).apply(a));
}

Hugh? Shouldn't it be simply:

private Stream<Integer> calculate(Stream<Integer> stream, Integer a) {
  return stream.map((x -> y -> t -> x + y * t).apply(b).apply(a));
}

Yes, it should, but Java 8 is not able to infer the type, so we have to help it by using “manifest” type (“manifest” is the word used in the Java specification for “explicit”). In order to make code cleaner, we may use some tricks:

interface F3 extends Function<Integer, Function<Integer, Function<Integer, Integer>>> {}

private Stream<Integer> calculate(Stream<Integer> stream, Integer a) {
  return stream.map(((F3) x -> y -> z -> x + y * z).apply(b).apply(a));
}

We may now name our function and reuse it when necessary:

private Stream<Integer> calculate(Stream<Integer> stream, Integer a) {
  F3 calculation = x -> y -> z -> x + y * z;
  return stream.map(calculation.apply(b).apply(a));
}

We may even declare the calculation function as a static member of a helper class and use static import to make the code event cleaner:

public class Functions {
  static Function<Integer, Function<Integer, Function<Integer, Integer>>> calculation =
       x -> y -> z -> x + y * z;
}

...

import static Functions.calculation;

private Stream<Integer> calculate(Stream<Integer> stream, Integer a) {
  return stream.map(calculation.apply(b).apply(a));
}

Unfortunately, Java 8 promotes using closures. I would have been much better to offer functional syntactic sugar to ease the use of currying. In Scala, for example, the example above would be written as:

stream.map(calculation(b)(a))

Well, we can't do this in Java. However, we can come close to it by defining the following static method:

static Function<Integer, Function<Integer, Function<Integer, Integer>>> calculation
    = x -> y -> z -> x + y * z;

static Function<Integer, Integer> calculation(Integer x, Integer y) {
  return calculation.apply(x).apply(y);
}

We can now write:

private Stream<Integer> calculate(Stream<Integer> stream, Integer a) {
  return stream.map(calculation(b, a));
}

Note that calculation(b, a) is not a function of two arguments. It is only a method returning a function of one argument after having partially applied two arguments (one by one) to a function of three arguments, resulting in a function of one argument ready to be passed to the map function.

The calculation method may now be tested in isolation.

Automatic currying

In the former example, we have applied currying by hand. However, as we are using a computer, we can ask it to do this for us. We can write a method that will take a two arguments function and return the curried version of it. This is very simple:

public <A, B, C> Function<A, Function<B, C>> curry(final BiFunction<A, B, C> f) {
  return (A a) -> (B b) -> f.apply(a, b);
}

Should we need it, we can write a method reversing the process. It will take as argument a Function of A returning a Function of B returning a C, and return a BiFunction of A, B returning a C:

public <A, B, C> BiFunction<A, B, C> uncurry(Function<A, Function<B, C>> f) {
  return (A a, B b) -> f.apply(a).apply(b);
}

Other applications of currying

There are other applications of currying. One of most important is simulating functions of more than one argument. In Java 8, there are functions of one argument (java.util.functions.Function) and functions of two arguments (java.util.functions.BiFunction). There are no functions of three, four, five or more arguments, like in some other functional languages. But these are not necessary. They are only like syntactic sugar for cases where all arguments may be evaluated at the same time. And in fact, this is the reason why BiFunction exists in Java 8: one frequent use of functions is to simulate binary operators. (Note: there is a BinaryOperator interface in Java 8, but it is used for very specific cases where all two parameters and the return value are of the same type. We will talk about this in a next article).

Currying is very useful when arguments of a function must be evaluated in different places. Using currying, one may evaluate one argument in some component, then pass the result to another component to evaluate another argument, and so on until all arguments are evaluated.

In short

Java 8 is far from being a functional language (and it will probably never be). However, it is possible to code in Java (even in Java < 8) using the functional paradigm. It simply has a cost. And this cost is much reduced in Java 8. But the developer who wants to write functional code has still intellectual efforts to do in order not to fall out of the paradigm. Using currying is one of such efforts.

Remember:

(A, B, C) -> D

may always be replaced with:

A -> B -> C -> D

even if Java 8 is not able to infer the type of this expression. You simply have to specify the type by yourself. This is currying, and it will always been safer that using closures.

In a next article, we will talk about Java 8 functional interfaces and how to deal with primitives.

Published at DZone with permission of its author, Pierre-yves Saumont.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Sanjeeva Samara... replied on Thu, 2014/04/24 - 1:08am

There are so many mistakes in this article - I don't want to even understand what you are trying to say. All in all, Java 8 is no better at FP than previous releases... it only makes life easier by simpler syntax, and we all know that !!!

Agudo Praena replied on Thu, 2014/04/24 - 2:55am

 It's an interesting article, Mr Saumont. It made me think about this in a way I never consider before. Thanks!

Pierre-yves Saumont replied on Thu, 2014/04/24 - 2:58am in response to: Sanjeeva Samaranayake

I think you are right at least on one point: you don't understand. You say you don't want to, but as you are commenting, I guess you in fact feel sad because you would like to understand, but you can't. Feel free to ask questions if you need.

Pierre-yves Saumont replied on Thu, 2014/04/24 - 3:13am in response to: Agudo Praena

Thanks for reading and commenting. Do not hesitate to share your thoughts about the subject.

Jeroen Wenting replied on Thu, 2014/04/24 - 3:57am in response to: Sanjeeva Samaranayake

 which is exactly what he's saying. And no, many people don't know that. They assume that Java is now a fully functional programming language just because it has lambdas...

Which is after all the reason they were added, to turn Java into a functional programming language "because OO is dead". It's even mentioned (almost in those words) in the official product presentation by Oracle.

It's nonsense, on every count, but it makes nice marketing.

Javier Maria Torres replied on Fri, 2014/04/25 - 3:16am

Maybe I didn't get it either, but I think you're somehow creating some confusion. In Haskell, a really FP language, there is no need to choose between closures and currying, because they are really different concepts meaning different things (capturing context outside a function vs partial function application). So it seems that the problem comes with the *Java* quirky implementation of FP concepts; as far as I can see, the use of *mutable* data. FP concepts are easier to grasp and apply to immutable data, but it becomes far trickier on a "reference-to-mutable-objects" language like Java.

Until research advances a bit more, I sincerely prefer to stick with plain old Java 6 and leave the advanced type system and the FP to Haskell. I prefer to stick to OO for certain things and FP for others; and due to the im/mutable dilemma, I find it hard to combine both. The type classes in Haskell come closer to a FP concept of objects, though.

Pierre-yves Saumont replied on Sun, 2014/05/04 - 11:52am in response to: Javier Maria Torres

I am not the one creating confusion. Those presenting Java 8 as a step toward functional programming are. What I mean is that you can program in Java using the functional paradigm, but it is not as simple as using lambdas and streams.

Java 8 is not a functional language because it does not help the programmer to use the functional paradigm.

So, you are perfectly right to continue using Java in the imperative style. Or you may use the functional style, but this has always been possible and is not related to Java 8. Java 8 pretends to be more functional. It is not completely untrue, but it is far from being enough to really help the programmer. So, regarding the functional orientation of Java 8, there is something (many things in fact) wrong.

If you can use Haskell, you are really lucky!

Carlos Saenz replied on Fri, 2014/05/09 - 2:15pm

 You don't "need" to choose between FP, AOP or OOP. the true is that you can use either of them as you need it... and the advantage of OOP is that if you need a part of a method to be functional you can reuse it later on the descendant classes... don't get into confusion.

Thang Mai replied on Wed, 2014/05/28 - 8:30pm

 Great post!, thanks for sharing

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.