As a Java/C#/C++ programmer I hear a lot of talk about functional languages, but have never found a need to learn one. I've also heard that the higher level of thinking introduced in functional languages makes you a better OOP/procedural language programmer.

Can anyone confirm this? In what ways does it improve your programming skills?

What is a good choice of language to learn with the goal of improving skills in a less sophisticated language?

Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise.
If this question can be reworded to fit the rules in the help center, please edit the question.

Be more than a Java/C#(+C++) programmer. There's a difference between a gigantic swiss army knife with a not-so-little pamphlet that outlines why you'd select blade X out of 40 and a blade you can carve out damn near anything you please with because it's both damn sharp and curves just right such that you can apply it's cutting power to a wide variety of circumstances without much thought. (with a bottle-opener in the handle of course)
–
Erik ReppenJul 3 '13 at 2:57

Since learning functional programming, I'm much more conscious about which concepts I work with are more naturally considered as "objects" (generally where mutation makes sense) and which are more naturally considered as immutable "values" (I think there's an important distinction, touching on where OO makes sense vs. when FP makes sense, but that's just my opinion).

I notice where my code includes side effects, and I'm more careful to isolate those places, making more of my functions "pure" functions. This greatly improves the testability of my OO code.

I'm more conscious about cycles in my data representation. (For example, I don't think you can write a function to convert a linked-list into a doubly-linked list in Haskell, so you do notice cycles quite a bit more in that language.) Avoiding cycles reduces the amount of synchronization you need to perform for your data structures to be internally consistent, easing the burden in sharing these structures between threads.

I'm more likely to rely on recursion (scheme's recursive looping constructs are things of beauty). Dijkstra touched on the importance of this in Notes on Structured Programming - recursive algorithms map very directly to mathematical induction, which he suggests is the only means to intellectually prove our loops correct. (I don't suggest that we must prove our code correct, but that the easier we make it for ourselves to do so, the more likely it is that our code is correct.)

I'm more likely to use higher-order functions. John Hughes' paper, Why Functional Programming Matters. It emphasizes the composability you get from employing functional programming techniques, higher-order functions playing a major role.

Also, as touched on in Jetti's answer, you'll find that a lot of FP ideas are being incorporated into newer OO languages. Ruby and Python both provide many higher-order functions, I've heard LINQ described as an attempt to bring support for monadic comprehensions into C#, even C++ now has lambda expressions.

@Frank: thanks for the pointer. I didn't include this in the answer, but the main objection I have to making Values into Objects has to do with the distinction b/w object interfaces (which are owned by objects) and operations (in which the relationships between objects are more primary than the objects themselves). 1 + 2 is mathematically equivalent to 2 + 1, but 1.+(2) is implemented differently than 2.+(1). There exist a number of SW problems than can be understood more naturally using operations than using object interfaces.
–
Aidan CullyFeb 8 '11 at 15:29

1

@Aidan Have you read William Cook's "On Understanding Data Abstraction, Revisited"? It delves into the differences between objects and ADTs, which is what you're hinting at.
–
Frank SheararFeb 8 '11 at 16:23

I wouldn't say it's guaranteed to make you a better OOP programmer, but it will introduce you to a new way of thinking, and that could make you better at problem-solving in general, not just in terms of OOP.

Given that objects are actually higher order functions, I found that learning FP stuff did help directly with my OOP. It is, as you say, more generally applicable/helpful though.
–
Frank SheararFeb 8 '11 at 9:18

Learning a functional language - Lisp for me - really helps when building parallel applications. Functional methods (state based, no side effects) are much easier to synchronize, and are easier to make thread safe since they only depend on their input. That means the only data you need to watch for a given area of code is the parameters you pass in. This also makes it easier to debug.

You'll find it also helps with threading libraries, which tend to expect pure functions as their tasks. It can also help indirectly, there are places where I'll write OO code in a kind of "functional style" where there's an "owning parameter" that has an implicit lock on a bunch of objects that it references and are used by the function. As long as you document your expectations (and unit test them) this can give you better multithreaded code with few locking issues. And few explicit locks.
–
МסžFeb 8 '11 at 3:50

I've never heard of Prolog being called a functional language. If I squint enough I can vaguely see how (parts of) Prolog could help with FP.
–
Frank SheararFeb 8 '11 at 9:17

1

Prolog isn't a functional language. It's a logic language. If you want a Prolog-like logic language that's integrated functional programming as well, mind, you can grab a gander at Mercury. Warning: It will hurt your brain a little even if you know Prolog already.
–
JUST MY correct OPINIONFeb 8 '11 at 10:56

Learning any other paradigm of programming will improve your programming skills in general. Programming, when it's not academic research-grade stuff (and even then, often), is basically problem-solving. Thinking, in a word. The various paradigms are different ways of thinking about problems and their solutions. So don't just think of it as "learning a functional language". Think of it as "learning a different way to think about problems and their solutions". Then you'll see the benefits of learning a language even if you never actually use it.

To address your specific question, I was a C++ programmer back in the days of yore (back before there was a standard for C++). I followed all the usual stuff with objects holding state manipulated by methods, etc. etc. etc. Then I stumbled across Haskell and learned (much of) it. (I don't think anybody ever truly learns Haskell.) The exercise seemed a bit wasted at the time until one of my colleagues, the tester assigned to my group, made an off-hand comment that my code was getting easier to test.

What had happened was that I'd started making my objects more and more immutable. Classes with complex mutable state started getting replaced with classes that cloned themselves with changes, returning the new objects. Shared objects started getting replaced with objects that had copy-on-write semantics (thus giving the illusion of lots of object clones without the memory overhead). Functions had no side effects unless absolutely necessary; the pure, mathematical definition of "function" was more and more the norm. All of this started happening in my code naturally -- no conscious thought got involved -- as I explored more and more of the functional programming space.

Now I make it a goal to learn at least one new programming paradigm every two years (even if it's only a minor extension paradigm like AOP) and at least two new languages within each paradigm (one as pure as possible, one more hybrid/practical). Each one has given me new intellectual tools to apply to all of my programming in any language, so the time spent learning them has not, in my opinion, been even slightly wasted.

I've said it before and I'll say it again, learning functional languages definitely improved my C#. It helped me understand lambdas (and helped me love them). It also made me realize how much I prefer functional programming (F#) when working with Asynchronous operations!

Machine code is nothing more then a list of side effects - commands that are directly executed by the processor. The side effects in C are different, rather then handling the registers and the physical hardware, you deal with a set of a abstractions and let the compiler do all the dirty work. C also lets you structure your side effects in loops and if then statements. C++ improves upon C by adding OOP and some much needed features to the language. Java and C# add garbage collection, and Python adds dynamic typing.

Even with all these features - dynamic typing, garbage collection, etc programs in these languages are still entirely based upon side effects. Functional programming languages, like Scheme, Clojure, Haskell, and ML are something different entirely, these languages are closer to math then to machine code. Rather then using side effects you pass values around functions.

What is a good choice of language to
learn with the goal of improving
skills in a less sophisticated
language?

I recommend Scheme, it is minimal and it was used in MIT's old introductory programming classes. The other functional programming languages are much harder to learn. Clojure brings along all the intricacies of Java with it, ML brings along a complicated static type system, Haskell is sometimes referred to as an academic language - it is not ideal for beginners, and so on. Scheme on the other hand is easy to learn and understand.

In what ways does it improve your
programming skills?

Almost all high level programming languages have functions and recursion - the concepts upon which functional programming is based upon. As such your knowledge of FP should be helpful almost everywhere, however, if you really want to program functionally you should use a language where it is a natural and efficient rather then trying to bend someone else's language design to your liking, that is to say you should use a functional programming language to do functional programming.