Software Development
Blogs and Discussion
developer.*
Books Articles Blogs Subscribe d.* Gear About Home

Functional Programming vs. OO

Joel has a fascinating recent post on functional vs. OO programming, which I found thanks to a comment from Danto a recent dev.* post.

What I found so interesting about this post is that it advocates and speaks to the power of an approach that I had long ago dismissed as sloppy or even frightening--the passing of free-floating functions as method/function arguments.

At the bottom of the post, he links to an amusing takedown of Java as an overly-rigid OO language. The overall point seems to be that functional programming is powerful and leads to ways of thinking that OO does not. I can't speak to the affect of one programming language or another on the way people think, but I can give my impressions of the funtional aspects of what I call free-floating functions.

What I mean by a free-floating function is a function that is not tied to a class. For example:

doSomething(thingToDo);

as opposed to

ThingDoer.doSomething(thingToDo);

The thing I've never liked about languages that allow free-floating functions is that they lead to sloppiness and confusion. Where does the magic non-name-spaced function exist? How can I access it? What do I need to import/include to get to it? What happens if there are different doSomething() funcions I want to use?

To my mind, Java and other OO languages provide a simple means of organizing functions as static methods that reside in an un-instantiatable object. The benefit you get with this approach is namespacing. The drawback is a slightly longer call. Is that really such a big deal?

What Joel describes as particularly powerful is the ability to pass a function as an argument, even one created on the fly in-line. He asks if my programming language can do this. Well, my language is Java and the answer is yes and no.

No, you can't pass a function as an argument nor create one inline. But, yes, you can accomplish anything this practice can accoplish--you just have to use slightly different means. And, actually, I think the result is Java is more readable and maintainable than the result you'd get with a free-floating function.

To pass a "function" to a method in Java, all you need to do is make the function part of an class and pass an instance of that object. This is trivial for any Java programmer and most Java programmers do this sort of thing every day.

In fact, I can easily implement Joel's map() function in Java.

public interface ThingToDo {
public int doThingToInteger(int i);
}

public class Mapper {

//Makes it so you can't instantiate this class.
private Mapper(){}

public static void map(ThingToDo doer, int[] intArray) {
for (int i = 0; i < intArray.length; i++) {
intArray[i] = doer.doThingToInteger(intArray[i]);
}
}
}

//And then somewhere in a method we'll have this line:

Mapper.map(new ThingToDo() { public int doThingToInteger(int i) {return i*2;}; }, a);

This is a trivial example (as Joel himself says), and yes, the inline class creation is ugly, though I would argue, not so much less ugly than inline function creation. A better practice would be to create the specific ThingToDo implementation as a separate .java file. Some would call this sort of thing clutter. I simply call it organization.

What the OO solution to this problem gives you, though, is some nice name-spacing, the potential for type safety in your map method and a potentially much more readable batch of code. What's the major issue with this?

I'll also admit that I'd never thought of farming looping itself off to a utility method. That's a terrific idea for all the reasons Joel argues. I'm just saying that there's no reason this can't be done in an OO language as easily as in a functional language.

Dynamicity (is that a word?)

>What the OO solution to this problem gives you, though, is some nice name-spacing...

C++ has namespace structures that are totally untethered from classes. Anything you can declare in the global namespace, or in a class, or in a function, can be declared within a named namespace that you yourself create in code.

>...the potential for type safety in your map method...

The argument of proponents of functional and dynamically-typed languages is precisely that things like type safety, when applied universally, are limiting. Generics and interface mechanisms were created specifically to get around these limitations. They were added to Java and C++ to support behavior that are very natural in functional and dynamically typed languages. That naturalness is key to the debate.

>...a potentially much more readable batch of code

This is quite subjective. And it's one example of how learning dynamic languages can change how you think about programming. I would argue that implementing in an OO language (esp. Java) these things that are inherently natural in functional and dynamic languages, is cumbersome, verbose, and rigid. Functional and dynamic languages drive toward a goal of expressing this behavior with utmost concision and elegance.

>there's no reason this can't be done in an OO language as easily as in a functional language

The concision and elegance mentioned above naturally contribute to ease as well. I understand the OO-minded view that functional and dynamically-typed languages encourage messy or disorganized code structure. But I would contend that this is because people who have settled into OO and resided there for too long begin to see OO-style structure as a requirement for organization, when that's simply not true. Think about it a little, and I think you'll see that this type of view is a bit closed-minded and a real barrier to advancement in any scientific or engineering pursuit.

There have been multiple responses to Joel's post that in effect answer his question in the affirmative. But I think Joel made a mistake when he asked that question. In particular, I think he should have asked it differently, because I don't think he meant to ask whether the general behavior was possible. Rather, I think his point was to ask how natural and elegant its expression is in language X.

My answer to that question, in the context of Java, C++, and C#, is: not very. (Though the planned feature additiosn I've seen for C# 3.0 look very promising. I think C# and its continued evolution is one of Microsoft's crowning achievements of recent years.)

A more poingant example of first class functions

While it is certainly true that you can implement map as a method in the class, that is missing the point. In a language with "free-floating functions" (which the rest of us simply call functions since everything in Java is a *method*), you can implement map once for ANY combination of list + function. In your example to program in a functional style you'd have to go around scattering map methods in each class or have your own base class from which everything else inherits. Not particularly DRY. Also, because of the type system you're either going to have to do some generics tricks or implement a ton of different map's to cover all the different combinations of methods and lists to iterate over.

Perhaps an example is in order, this comes from Ruby which perhaps will be more to your syntactical tastes:

list = [1,2,3,4,5,6] #array of numbers
list.each {|i| puts i if i%2 == 0} #print out even nums
list.each {|i| puts i if i>4} #56

and then since you've got the really most basic stuff like each going you can take this idea of passing in anonymous functions (called lambdas) and do all sorts of fun things

list.reject {|i| i > 4} #[1,2,3]
list.partition {|i| i%2 == 0} #returns 2 lists [2,4,6], [1,3,5]
list.inject {|sum, i| sum += i} #21

These methods and several others are available for any collection in any class in any file anywhere. This is all without losing the namespaces that classes give you. The point is, you can do C++ in C with function pointers, the fact that's it's possible doens't mean C is a good language for object oriented programming. The same applies here to Java and functional programming, the language just doesn't support the needed functionality to make it useful. As the previous commenter stated, C# 3.0 (while I detest MS and have never used C# professionally) is adding things like anonymous functions (lambdas) so you will be able to pull off *some* of these tricks there.

Dynamism . . .

. . . is I think the word WaterBreath is looking for above.

I'm not sure I understand David Koontz's point that:

In your example to program in a functional style you'd have to go around scattering map methods in each class or have your own base class from which everything else inherits.

That's not true at all. You could implement something like this any number of ways in Java, such as in a static method, or in a class that other methods instantiate and call methods on, or as some sort of remote service.

Developers tend to get into my-language-is-better-than-yours pissing contests (again, I see Calvin peeing on various corporate logos -- see this comment I made in another post), and I don't want play that game if at all possible (and I'm not accusing either WB or DK of doing so either). I'm sure that functional programming has its uses and its merits. My only point was that the particular problem Joel presented was certainly solveable in Java. I remain convinced that it is.

I had occasion recently to re-visit a post of mine from last year in which I dug into the different mindsets developers get into when they think linearly (solving problems through iteration in code) and when they think in sets (which is how SQL operates). This discussion actually reminds me quite a bit the points I raised (and the larger point I think Joel was trying to make) that the development language you use affects how you think about solving problems, and that sometimes it can box you in.

The right tool...

My primary point was, as I noted, that it's not enough just to verify "yup my language can do that". The question is, will you use it? Is it more efficient than the method you already knew? If it isn't, you're not likely to use it. And not likely to consider that it might be easier than what you're already comfortable with, if you try a different language. Sometimes doing the same job in a different way in the same language is worse, but doing it that way in a different language is just plain better.

"...Right tool for the job..."

Everyone knows some languages are good at some things and others are good at others. But we'll never know what exactly those things are unless we shop around. It's not enough to be "sure that functional programming has its uses and its merits". I'd encourage you to take up the goal I did recently: find out what those uses and merits are!

Joel's argument (and Paul Graham, and Steve Yegge, and... ) is that not only will you find new tools you never had before, but you'll find that you can think about solutions in ways you never did before. And that will help you even if you stick with the old stand-by language. (If it's expressive enough. Doesn't matter how much you know about generics and dynamic typing, it won't make your PL/SQL more concise or elegant. Bleh.)

Comment viewing options

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

User login

About our advertising.

Atom Feed

developer.* Blogs also has an Atom feed, located at this url.

Click here for more information about Atom.

A Jolt Award Finalist
Software Creativity 2.0
Foreword by Tom DeMarco

Recent Posters

Based on most recent 60 days, sorted by # of posts and name.

Google
Web developer.*

Who's online

There are currently 0 users and 23 guests online.

Syndicate

Syndicate content
All views expressed by authors, bloggers, and commentors are their own and do not necessarily reflect the views of developer.* or its proprietors.
Click to read the Copyright Notice.

All content copyright ©2000-2005 by the individual specified authors (and where not specified, copyright by Read Media, LLC). Reprint or redistribute only with written permission from the author and/or developer.*.

www.developerdotstar.com