Enterprise Software

Where functional programming fits in

Functional programming (FP) may be the solution to some of your development problems. Here's what to know if you're considering using FP in your work.

 

In the last few years, functional programming (FP) languages and the ideas the languages implement have risen to prominence. This is partially due to various languages that contain some functional ideas becoming more mainstream (e.g., Ruby), and developers learning how to better leverage those functional features. It also helps that the .NET platform (particularly C#) has adapted and adopted many FP ideas and become more of a hybrid model. To further push things along, the Java platform (with Scala) and the .NET platform (with F#) now have full-featured languages that support the OO and FP paradigms at the same time; in .NET 4, F# is given the same weight as C# and VB.NET. Now that most developers have the ability to tap FP languages and concepts, when does it make sense to do so?

Here are a few things to keep in mind if you're thinking about using FP:

  • FP code does not have "side effects."
  • In FP, there are no literal values, simply functions that always return the same value.
  • Many FP languages have "lazy evaluation," where functions are not evaluated until their results are needed; in such a case, if you define "x" to be equal to "y + 5," "x" will be defined with no value until you try to use the value of "x," at which point execution returns to its definition, and the value is calculated and provided to the caller. This is a boon (better performance) and a curse (non-deterministic values in some cases) at the same time.

While none of these traits of FP languages should be considered hurdles, they do represent a radical change in thinking. You can leverage FP languages in ways that may dramatically improve the code writing process and the quality of code. However, if you FP languages, you need to be mindful that you aren't overengineering or overthinking the problem, especially if it requires using a technique or a language that may confuse other code maintainers.

In my experience (which is limited when it comes to using FP in production code), I find that FP techniques and languages shine in algorithmic coding scenarios. Maybe I am stereotyping FP based on its "everything is a function" approach, but I find that FP works very well for that kind of work. Math, for example, is very nice in FP. A few months ago, I saw an F# sample where the author defined various units of measurement as functions that provided conversion, so you could add 10 meters and 45 inches in code perfectly naturally. Another impressive example of FP's strength was the Xbox Live ranking system; it was rewritten from C# into F#, with about 10% of the total lines of code, and ran at 95% of the speed. Again, it is an example of algorithmic code.

Where FP loses its advantage is in the basic "library glue code" and creation of structure classes that constitutes much of the modern, mainstream software development experience. If your code consists of a lot of classes that look like structures, and most of your "algorithm code" is shuffling properties from one object to another, using FP just will not be worth the effort, unless your project is going to use it anyway.

In summary, FP is not necessarily the answer to all of your development challenges, but it is something worth checking out and seeing where it can fit into your toolbox.

J.Ja

Disclosure of Justin's industry affiliations: Justin James has a contract with Spiceworks to write product buying guides; he has a contract with OpenAmplify, which is owned by Hapax, to write a series of blogs, tutorials, and articles; and he has a contract with OutSystems to write articles, sample code, etc.

---------------------------------------------------------------------------------------

Get weekly development tips in your inbox Keep your developer skills sharp by signing up for TechRepublic's free Web Developer newsletter, delivered each Tuesday. Automatically subscribe today!

About

Justin James is the Lead Architect for Conigent.

28 comments
mandrake64
mandrake64

I have to take a fairly pragmatic approach to programming in my workplace, spending a lot of time maintaining C++, Java and Fortran code written by others. It makes sense to use FP if, and only if, the result meshes well with existing code and does not result in a deterioration in performance and code readability. Much of the time, the emphasis is on adding functionality that is fast and achieves most, but not necessarily all, of the targetted goals. The 80/20 rule in action. Then it's on the next improvement. You have to match the coding style to the program you are modifying. And there are no extra points to be gained from your operations manager if you are doing a lot of extra coding for no practical gain.

bobbobbob789789
bobbobbob789789

>> In FP, there are no literal values, simply functions that always return the same value. Where did you hear that? >> Where FP loses its advantage is in the basic ?library glue code? and creation of structure classes that constitutes much of the modern, mainstream software development experience. If your code consists of a lot of classes that look like structures, and most of your ?algorithm code? is shuffling properties from one object to another, using FP just will not be worth the effort, unless your project is going to use it anyway. What in the world makes you say this? Can you back this up with anything that's concrete and not circumstantial?

DukeCylk
DukeCylk

What is it about C# in particular in the .NET platform that has adapted and adopted many FP ideas that VB has not. Honestly, is there something about VB that precludes it or causes you to exclude implicitly by emphasizing C#. Sorry if I drag this discussion into that tired debate, but if you must phrase something that way, there must be something behind it. Before all you repsond with that VB is not a real language, I know that you really mean that most C# programmers were probably better trained to be true classical programmers, and VB people are for the most part hacks; I am a VB guy, and a hack, guilty as charged...but I see so many C# examples, and have learned to translate everyhting I've needed into VB. Operative terms are "I've needed"!

werlid
werlid

well, regarding the Erlang experience, I think FP a very promising paradigm which can make big difference.

Zeroesque
Zeroesque

It seems important to me to mention Google here. Joel Spolsky points to Google's MapReduce as a monumental piece of code that is implemented functionally. Also, developers have to get used to recursion and "f(f(x))" type of thinking.

jkameleon
jkameleon

FP seems pretty suitable for that, as far as I can tell. No states and side effects to deal with, and even more important- loops are declared as list operations. This way, compiler can decide whether and how the processing within a loop is going to be distributed among processors in multicore machine.

Justin James
Justin James

Do you any use for functional languages (or the functional aspects of hybrid languages) in your work? Or are they just a novelty for the CS theorists? J.Ja

Justin James
Justin James

">> In FP, there are no literal values, simply functions that always return the same value. Where did you hear that?" That is part of the definition of "functional programing". For example: def x = 5; x is not a literal value equal to "5", x is a function which always returns 5. Is it *equivalent* to a literal? Sure, I suppose so. But it's a different way of thinking about things, too. ">> Where FP loses its advantage is in the basic ?library glue code? and creation of structure classes that constitutes much of the modern, mainstream software development experience. If your code consists of a lot of classes that look like structures, and most of your ?algorithm code? is shuffling properties from one object to another, using FP just will not be worth the effort, unless your project is going to use it anyway. What in the world makes you say this? Can you back this up with anything that's concrete and not circumstantial?" What makes me say this? Well, I've played around with FP a bit, and I've been programming for a while. I cannot see how, in the kind of code like: object1.propertyA = object2.propertyG; if (object1.propertyJ > constant5) { object1.methodGo(object10.propertyL); }} gets any kind of benefit from the FP paradigm. The close will end up looking very, very similar once you account for language syntax, it will execute the same, and it will take the same lines of code. There's just no advantage that I see. Now, maybe I'm wrong. I would not mind being wrong at all on this score. I'm a pretty big fan of FP, and if I wasn't, I wouldn't have written an article trying to show that it has a place in the modern developer's toolkit. If you can show me how that kind of code can be substantially improved by FP, I'd love to see it. Better yet, put together an article showing how this kind of code can be really improved by FP, and I will have it published here in TechRepublic as a "guest editorial". Deal? J.Ja

Justin James
Justin James

Why say "C# in particular" but not VB.NET? A few reasons, some of which you have already mentioned: * Lambdas are essential to this style of programming, and until VB.NET gets multi-line lambdas in VB 10 (.NET 4), it is virtually useless for this. * VB.NET developers, as a community, do not seem as interested in this kind of work. They are focused very sharply on particular tasks, and in comparison, there are pockets of the C# community (hardly a majority, I may add) that are doing a lot more experimentation. * Documentation matters... when you see 3 times as many C# books on the market as VB.NET books, it is harder to find out how to do these things in VB.NET. It also reflects on the interests of the respective communities. Likewise for example code (as you've pointed out). The overwhelming majority of sites post example code exclusively in C# at this point. A few years ago it was different. Again, this comes back to the community. Why is the VB.NET community not taking the time to psot examples, tutorial, etc.? From personal experience, I can tell you that I used to use VB.NET for example code. I think I switched to C# sometime either early this year or late last year (I know that late last year was the first time I ever used C# in any kind of example, for a presentation... that code is still ugly because it is half Hungarian notation and half camel case!). J.Ja

Justin James
Justin James

You are right that parallel processing is a great use case for FP. F#, for example, has parallel stuff built into it for that reason. J.Ja

lars.nielsen
lars.nielsen

It's great to see functional languages making a comeback after so many years hiding in the wings! I remember learning LISP that one of its advantages was cited as improved productivity (once you could figure out how to code in it). If you look at the work of Simon Peyton Jones you can see there is a long history of research into the application of parallel processing to functional languages - they do fit together very well.

jck
jck

I use Excel all the time! :^0 Ah! All this nomenclature. I'm done. I'm going to flip burgers at Wendy's or something.

jk2001
jk2001

It's useful for learning how to program, because FP languages make it hard to write sequential code. You end up programming at a "higher level" - instead of writing loops, you write filters. Instead of writing the Visitor pattern, you learn to transform data with generic programming techniques (aka map or apply). Then, you go back to coding in whatever procedural, OO language, and bring back these FP techniques, and the code looks better, or at least doesn't take so long to write. Maybe people find it confusing.

Shaunny Boy
Shaunny Boy

...as I believe it can finally teach me how I'm suppose to program! All too often does a function mutate into a polymorphic method with overloaded overloads of none static gobble-dee-goop. Reminds me a bit like how I learnt to drive, and my current driving style.

Ed Woychowsky
Ed Woychowsky

I use a lot of XSLT in my day job, it has definite functional leanings there. The hardest things to learn are that recursion is the way to go and that variables are set once. Unless, of course, you recurse, bet then it's a whole new variable.

Mark Miller
Mark Miller

Maybe I was getting confused about this as well. I had the same thing in mind as you did. Bobbob's comment had me remembering back to my CS training. I THINK the correct way to look at it, as opposed to what you said about 5 being a function literal, is that if you say: a = 5 What you're doing is defining a function 'a' that returns the literal 5. Another rule I remember about functional languages is that you cannot assign a value to a variable twice. Maybe this has something to do with it.

DukeCylk
DukeCylk

I must admit it is tempting to switch to C#, if not just for the career 'street cred', but I am a one man show in a sea of non-programmers, who hired me because they already had a bunch of VB code that needed fixing. I am constantly building on top of exisiting code and have no time to go back and change what I've already written. My employers would probably not like it if I switched to C# cause if I left they wouldn't have a prayer on how to work with it. Funny thing is that their previous stuff wasn't really VB .Net, but VB script that automated their CAD processes! I've read where MS plans starting with 2010 that VB and C# will hence forth be developed in paralell, and be virtually equal capability...is this what you are hearing as well? Great work JJ, keep up the interesting topics.

SObaldrick
SObaldrick

Now, I am not aware of current FP languages, I was brought up with assembler, BASIC and C, but my generation spent a lot of effort replacing functional programming with OO programming, for a V. good reason. (To improve the quality of the code, at the expense of efficiency, I believe). (It was during the rise of OO languages such as Java and C#, that I detached myself from programming - no connection.) I would have thought that the concept of 'encapsulation' in OO languages would lend itself more easily to designing a parallel processing architecture. Les.

guy
guy

One of the first apps I wrote was an xslt 'stylesheet' that converts financial transaction data from one format to another - it has worked daily for four years, I don't know if that's because it is a functional app or just luck, but to me xslt has always felt more robust...Perhaps because it is more unforgiving in the design stage? I enjoyed writing in this new way, mental gymnastics but worth it.

Mark Miller
Mark Miller

I should've added this to my comments: [i]define (good-enough? guess previous-guess) (< (abs (- guess previous-guess)) (/ 1 (if (>= guess 100) guess (* guess 1000)))))[/i] I realized today what I showed here is not unique to FP. You can do this in C/C++/Java/.Net as well: int GoodEnough(double guess, double previousGuess) { return (abs(guess - previousGuess) - 1.0 / ((guess >= 100.0) ? guess : guess * 1000.0)); } What's different is, like I was saying earlier, there are a lot of elements here that are not themselves functions. For example you have to explicitly say "return" to return a value (functions do that inherently in FP). The mathematical and boolean operators are features of the language. They are not functions. The implication of this is it's not possible, or tricky, to redefine their meaning (though this is possible in most OOL's, to varying degrees). In C/C++ it's possible to use the preprocessor to redefine reserved words and operators (though an operator would have to be replaced with one the underlying language considers legal, and so is not too useful). It becomes tricky to use redefined elements across macros, because you have to consider what they will expand into and whether that will work with the syntax rules of the underlying language. Pascal wouldn't have allowed you to redefine anything, as I recall. I'm not trying to say that one approach is superior to another. That's not the point. I'm pointing out the architectural differences, and some of their implications.

Mark Miller
Mark Miller

[i]The comments about asynchronous message passing and concurrent processing surprise me. I was under the impression that the BIG advantage of OOP over FP was the ability to perform both of these without having to worry about the complications of switching between functions.[/i] Maybe we are using different definitions for asynchronous message passing. What I was talking about was that a method could send a message to a shared object. The shared object would inherently be thread safe, and would be able to control how many messages it responded to at a time. The sending object could elect to block on the method call, or continue and wait for a response later. I've programmed in Smalltalk, C++, and Java. Smalltalk does message passing strictly synchronously, from what I've seen. It is possible to spawn threads in it, but that still requires enclosing code inside a closure and then sending a special message to it, telling it to execute the code in a separate thread. There's also a future-promise pattern that I've seen some use, which sounds similar to fork-join. When I worked in VC6 years ago you could start a thread on a method, but you had to supply the pointer to it. Method calls were certainly not asynchronous by themselves. I've seen a fork-join pattern used in Java for concurrency, but that still involved synchronous method calls. I think if any OO language could implement asynchronous message passing smoothly it would be Smalltalk. It's just a matter of the VM supporting it. To date the only language I've heard of that supports asynchronous message passing natively is Erlang. I've programmed in Pascal before, so we have a common ground. It's been years since I programmed in it, so I may be rusty. Most of my procedural experience is in C. The way that Pascal worked was you had different kinds of expressions that would each be interpreted differently. What I remember is that Pascal was more statement based than expression-based. I think it had strict rules about where expressions could go. I was trying out Newton's method of finding a square root not too long ago. So I'll use that as an example. There's a check that needs to be done, we'll call it "GoodEnough" to see if we need to iterate some more. In Pascal this would be written as: boolean GoodEnough(real guess, real previousGuess) var real precision; begin if guess >= 100 then precision := 1.0 / guess; else precision := 1 / (guess * 1000.0); if abs(guess - previousGuess) < precision then return true; else return false; end; I can't remember if Pascal supported boolean expressions like: return (x < 100); Anyway, you can do that in C. I don't know if this is a hard and fast rule for FP, but in the ones I've used code can be treated as data, and data can be treated as code. Also, there are few special forms. In Lisp and Scheme the execution model is pretty simple: Everything is a list. Code is executed as (function parameters ...), where the first symbol always refers to a function, and the rest are considered as parameters to the function. It uses recursive evaluation, so if there are nested lists, the innermost list is evaluated first, followed by the ones that enclose it. In Lisp it's possible to control the parser. So you can say "make this list just data, don't evaluate it", or you can do that with just part of a list. Scheme has some special forms where it evaluates certain list types differently than typical expressions, but in terms of style it keeps things pretty consistent. Lisp is similar. So in Scheme the above function can be written as: (define (good-enough? guess previous-guess) (< (abs (- guess previous-guess)) (/ 1 (if (>= guess 100) guess (* guess 1000))))) Note the "if" form embedded inside the inversion expression. As the lists are evaluated it comes upon the "if" form and evaluates it inline, returning either "guess" or "guess * 1000" to the outer expression, which begins with "(/ 1". As Justin was saying in his article, in pure FP there are no side-effects. So in evaluating the "

SObaldrick
SObaldrick

The overall structure was still oriented around a process of executing instructions linearly, with branching. --- Still don't get it .. one of the popular 'high' level languages when I was programming, was PASCAL. Under your explanation above, I would have called this a 'functional' language. (And yes, learning it did involve a change of mindset, from using languages such as BASIC and FORTRAN). The comments about asynchronous message passing and concurrent processing surprise me. I was under the impression that the BIG advantage of OOP over FP was the ability to perform both of these without having to worry about the complications of switching between functions. Remember that I stopped programming about the time of the emergence of OO development and moved into OOA/D. The great thing about OOA/D over FA/FD is that we no longer had to think of process as linear. Emphasis was placed on parallel (or concurrent) processing and a large part of OOA/D effort was spent on checking for deadlocks and conflicting processes. It surprises me to learn that this change in attitude did not move into OOP. Once the problems have been sorted out in the OOD model, there should be little to worry about when if comes to coding, in this respect. This is all in theory .. I have never seen a pure OO project go from analysis to test. In fact .. (but that's another story). Les.

Mark Miller
Mark Miller

I'm not contradicting the statement that FP is a tool that's never been in mainstream use. It hasn't. There have been things called functions in procedural languages, but it's seemed to me they were only there as a convenience, to offer a way to return a value, based on an input. The overall structure was still oriented around a process of executing instructions linearly, with branching. FP is just one model of computing. Software engineers are now seeing there may be some advantages to using it. Its first major application was in symbolic AI in the 1960s, and thereafter, but it didn't get used much beyond that. Some functional programming got put into OOP with Smalltalk-80, in 1980. It included closures, which first appeared in Lisp, I think. A closure in Smalltalk is a function that captures its environment, but it's inside an object container. You can even do lambda calculus with them. This pattern has since been replicated in other OO languages like Ruby, and more recently in .Net 3.5. You don't get the full feel of FP in these OO languages, though, because objects are "in the driver's seat". The cutting edge way they take advantage of concurrent processing now is via. the fork-join and promise patterns. In pure FP it can be done without having to set up these explicit structures. I think the object paradigm could be updated to allow asynchronous message passing that would also allow implicit blocks on method dispatching, or at least implicit cloning of a target object for thread safety, which could allow OO to take advantage of concurrency without having to jump through hoops.

SObaldrick
SObaldrick

Hmmm .. are you contradicting the above statement? Time for me to sit back and observe. Les.

Mark Miller
Mark Miller

I'll just get this out of the way first: "What did OOP replace?" OOP replaced procedural programming (or, in most cases it became "procedural 2.0"). Rather than writing this: void func(void) { // some code } You now have: class SomeClass { public void func(void) {/* some code */} }; rather than calling: func(); you write: SomeClass a = new SomeClass; a.func(); Functional programming adopts the philosophy that everything is a function (just as in OOP everything is an object...or at least it's supposed to be). In C# you might write: int a = 2; which means "Assign an Int32 literal object to variable 'a'." In a functional language like Scheme the same thing would be: (define a 2) which means "Create a function that returns literal '2' and bind it to symbol 'a'." Think of it translated like this: int a(void) { return 2; } This looks procedural, and it's supposed to. I'm not using any objects in this example. At a prompt you could type: > a and the result would be: 2 What happened is it did not merely go to a memory location (pointed to by 'a'), fetch the value '2', and print it. The idea, anyway, is it's supposed to reference the function bound to 'a', call it, receive the value from it, and print it. So 'a' is bound to a first-class function, just like, for example: (define b (+ 5 4)) It creates a function (this time with some recognizable code, computing 5 + 4) and binds it to the symbol 'b'. So if we type: b we get: 9 The other thing about functional languages is that you're supposed to only be able to bind a value to a symbol once. So in C# terms (I think, or C++), think of all variables as const's. Something that I still haven't gotten used to with FP is that you're supposed to not think of state change as a linear process, where you go: int a = 1; // do some stuff // and then later... a = 3; // do some more stuff Instead what's supposed to happen is state change takes place on the stack. So if you want to change a symbol's value, that's where you do it, usually using recursion. So loops look something like this: (define (loopy a) (cond ((> a 9) a) (else (loopy (+ a 1))))) What you get out is 10, or whatever value you start with if the input to "loopy" is more than 9. I found this article on FP a few years ago. It's written for the FP newbie, called "Functional Programming For the Rest of Us": http://www.defmacro.org/ramblings/fp.html

SObaldrick
SObaldrick

I used to work with functional analysis and functional design. These concepts (during my career) have been replaced by OOA and OOD. What did OOP replace? Les.

philip.robar
philip.robar

Since FP has been, and at least to this point in time still is, a niche in the programming world it was never "replaced" with an entire generation's effort by OO programming. I suspect that you meant to say that imperative programming has been, to some extent, replaced or more accurately enhanced with OO programming. Also, since FP has never been a mainstream programming tool it can't be said to be making a comeback. Perhaps, with the emergence of languages like Erlang, Haskell, Ruby, Scala, and Javascript, and the continued use of LISP, one might say that there is a growing awareness of FP's strengths. One of those strengths, which the author of the article didn't mention, is how ideally suited FP techniques are for implementing solutions that take advantage of the multi-processor hardware which has become so common.

Editor's Picks