In first year, we learned about functional programming. We learned about the evils of mutation, and the power of stateless programming. Unfortunately, everyone abandoned functional programming the second they got the chance. They picked Java (or C++ (OR EVEN C!)) instead of Scheme because they were more comfortable with imperative programming.
The problem is that most functional languages don't have great support for industry-strength development. They don't let you quickly build GUIs, or have built in support for design patterns. Granted they don't need a lot of support for design patterns, since the language itself makes them obsolete. All this really means though, is that functional programming languages shouldn't be your base language for your application. It is still a good idea to have small functional modules, or even better, to just code with functional programming in mind when you write your imperative code.
I realize that imperative and functional are somewhat conflicting paradigms. One revolves around modifying state, and the other tries to avoid it as much as possible. Like most things, it's a balance. Not every object needs to be mutable, and not every function needs to be recursive.
Here's a few things that I have found useful in imperative programing.
It really helps to have variables that don't change their values after initialization. If you need to change a variable's value, you can make a new variable. This makes debugging much simpler, and it's easier to think about your code. However, this doesn't always make sense in imperative programming. If you are making a counter, this obviously doesn't apply, and making counters the "functional" way is unintuitive. On the other hand, if you are modifying a string in several ways, several immutable variables might make sense:
Code like this is much simpler to test, since you can easily see the progress of the transformation of your string.
It makes sense for some object to be immutable. This applies well to plain data objects, or objects that simply aggregate related information. Immutable objects are inheritable thread-safe and simpler to code. You don't need to worry about coding complicated methods like clone (in Java). However, if you make every object immutable, you end up with really awkward looking object oriented code. Again, it's a balance.
Some objects are naturally recursive, so it makes sense that operations on them should be recursive. This makes the code very natural. However, you shouldn't use tail recursion in imperative programming. You are essentially writing an awkward for loop. In fact, some compilers will optimize tail recursion and for loops into the same thing.
Functions that don't modify state are much simpler to think about. They also make multi-threading those functions much simpler, since you minimize the amount of ways to change values. This is a hard rule to follow gracefully in a paradigm that revolves around methods changing state. The key is that not every function needs to change state. You have to choose side-effect free methods carefully. Static functions are usually great candidate for this.
This is just a fancy word for a function that doesn't depend on anything other than it's parameters. If I call the function with the same parameters, I should get back the same result, regardless of the outside circumstances. Writing functions like this makes threading much simpler, since these functions don't depend on outside state. Functions like these are also very simple to test since they don't have any external dependencies.
These are just a few things to keep in mind when you are writing code in object oriented code. It'll make your imperative code much cleaner and simpler to code, test, and debug.
<Watching Troll 2>