The Artima Developer Community
Sponsored Link

Java Buzz Forum
Why Functional Programming in Java is Dangerous

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Elliotte Rusty Harold

Posts: 1491
Nickname: elharo
Registered: Apr, 2003

Elliotte Rusty Harold is an author, developer, and general kibitzer.
Why Functional Programming in Java is Dangerous Posted: Jan 20, 2013 7:15 AM
Reply to this message Reply

This post originated from an RSS feed registered with Java Buzz by Elliotte Rusty Harold.
Original Post: Why Functional Programming in Java is Dangerous
Feed Title: The Cafes
Feed URL: http://cafe.elharo.com/feed/atom/?
Feed Description: Longer than a blog; shorter than a book
Latest Java Buzz Posts
Latest Java Buzz Posts by Elliotte Rusty Harold
Latest Posts From The Cafes

Advertisement

In my day job I work with a lot of very smart developers who graduated from top university CS programs such as MIT, CMU, and Chicago. They cut their teeth on languages like Haskell, Scheme, and Lisp. They find functional programming to be a natural, intuitive, beautiful, and efficient style of programming. They’re only wrong about one of those.

The problem is that my colleagues and I are not writing code in Haskell, Scheme, Lisp, Clojure, Scala, or even Ruby or Python. We are writing code in Java, and in Java functional programming is dangerously inefficient. Every few months I find myself debugging a production problem that ultimately traces back to a misuse of functional ideas and algorithms in a language and more importantly a virtual machine that just wasn’t built for this style of programming.

Recently Bob Martin came up with a really good example that shows why. Here’s a bit of Clojure (a real functional language) that returns a list of the first 25 integers:

(take 25 (squares-of (integers)))

This code runs, and it runs reasonably quickly. The output is:

(1 4 9 16 25 36 49 64 … 576 625)

Now suppose we want to reproduce this in Java. If we write Java the way Gosling et al intended Java to be written, then the code is simple, fast, and obvious:

for (int i=1; i<=25; i++)
    System.out.println(i*i);
}

But now suppose we do it functionally! In particular suppose we naively reproduce the Clojure style above:

import java.util.ArrayList;
import java.util.List;

public class Take25 {

    public static void main(String[] args) {
        for (Object o : take(25, squaresOf(integers()))) {
            System.out.println(o);
        }
    }

    public static List<?> take(int n, List<?> list) {
        return list.subList(0, n);
    }

    public static List<Integer> squaresOf(List<Integer> list) {
        List<Integer> result = new ArrayList<Integer>();
        for (Integer number : list) {
            result.add(number.intValue() * number.intValue());
        }
        return result;
    }

    public static List<Integer> integers() {
        List<Integer> result = new ArrayList<Integer>();
        for (int i = 1; i <= Integer.MAX_VALUE; i++) {
            result.add(i);
        }
        return result;
    }

}

Try to run that. Go ahead. I dare you....OK, recovered from the heap dump yet?

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:2760)
	at java.util.Arrays.copyOf(Arrays.java:2734)
	at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
	at java.util.ArrayList.add(ArrayList.java:351)
	at Take25.integers(Take25.java:30)
	at Take25.main(Take25.java:9)

How did Clojure handle a function that returns every single int, while Java crapped out? The answer is that Clojure, like pretty much all true functional languages (and unlike Java) does lazy evaluation. It doesn't compute values it doesn't use. And it can get away with this because Clojure, unlike Java, is really and truly functional. It can assume that variables aren't mutated, that the order of evaluation doesn't matter, and thus that it can perform optimizations that a Java compiler can't. And this is why functional programming in Java is dangerous. Because Java isn't a true functional language, the JIT and javac can't optimize functional constructs as aggressively and efficiently as they can in a real functional language. Standard functional operations like returning infinite lists are death for a Java program. That's why functional programming in Java is dangerous.

You may object that I've set up a straw man here. OK, you can't return a list of all the integers (or even all the ints) in Java; but surely no one would really do that. Let's look at a more realistic approach. Here again I use recursion to compute the squares rather than a loop:

public class Squares {

    public static void main(String args[]) {
        squareAndPrint(1, Integer.parseInt(args[0]));
    }

    public static void squareAndPrint(int n, int max) {
        System.out.println(n * n);
        if (max > n) {
            squareAndPrint(n + 1, max);
        }
    }

}

That will run. But now suppose I don't want the first 25 squares but the first 25,000:

Ooops. Stack overflow. This is why in XOM I was very careful to use loops rather than recursion, even in places where recursion was much clearer. Otherwise a carefully configured XML document could have caused a XOM-using program to dump core. Avoiding arbitrarily large recursion in non-functional languages like Java and C isn't just a performance requirement, it's a security requirement too!

Now before the flames begin, let me be clear about what I am not saying. I am not saying that functional programming is a bad idea. I am not saying that functional programming is inefficient. I actually love functional programming. Like my colleagues I find find functional programming to be a natural, intuitive, and beautiful style of programming but only when it's done in a language that was designed for it from the beginning like Haskell. Functional idioms in Java are performance bugs waiting to bite you.

Read: Why Functional Programming in Java is Dangerous

Topic: IntelliJ IDEA: Generate equals, hashCode and toString with Google Guava Previous Topic   Next Topic Topic: Towards a Theory of Test-Driven Development


Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us