Wednesday, August 22, 2007

Functional Programming in Imperative Languages

This post is a bit techie here... bear with me! :)

I've been toying and experimenting with functional programming these few weeks. Ever since I got into a bit of trouble for not debugging my software properly, I've been thinking: "How come software engineering is SO difficult to debug? and integration is every software engineer's nightmare. We keep having to do regression testing again and again and again till the cows come home, and even then, we can't be reasonably sure that we haven't missed out some distant but destructive bug." Scary.

And part of the reason is due to the heavy use of stateful variables, which keep on getting changed as the program executes. Functional programming (FP), in its purest form, is super-easy to debug, as it is impossible for unforeseen side-effects to occur (due to its inherent property of referential transparency).

So I was thinking, "There must be a better way to write software than to have to do all this testing - it's simply... not effective enough. Unit testing is NOT the way to go - it's the entire foundation of writing software that's not good enough."

The main problem with using FP to write commercial-level software is that for the past 40+ years, the most widely used programming languages to write commercial languages are imperative languages. And I bet you that at least 90% of all software engineers have to write in imperative languages. And functional languages, to put it mildly, have very exotic syntaxes and grammars. Imagine the huge costs to organizations if they have to retrain an entire generation of software engineers. So the companies prefer to keep the status quo.

*******
So why don't we use a balanced approach? We can borrow the key principles of FP that make them so useful, and apply them to our favourite imperative languages (e.g. C++, C, Visual Basic, Delphi, etc. etc). That way, we gain the best of both worlds - and even better, we don't have to learn a totally new language (like switching from writing English to writing Chinese) just to benefit from FP.

So I've been trying to apply FP principles to Visual Basic 6. Yes, THAT toy language. And it's very interesting. Like making sure that I do NOT change the value of any variables within a function. And I'm thinking of how to implement higher-order functions (functions that accept other functions as parameters) in VB6.

And hee, thank God, the code is so much more readable, cleaner and more predictable! And... even more cool is the fact that the number of lines of code is cut by between 1/3 and 2/3!

Of course, there's a slight disadvantage - performance issues due to overhead of function calls (esp recursion). But that can be resolved by judicious usage of stateful variables to cache the output of any function.

Hence, using FP principles in imperative languages should help reduce the complexity in any given class that tends to balloon when you keep using member variables to cross-reference other member variables... anyone who's tried to do software maintenance on a class that's been inherited (pathetic pun intended) from the guy before him, who in turn inherited it from another guy... ad infinitum.

Cool. :D my first ever techie rant/proposal on this blog. if you're a fellow techie, what do you think of this idea?

4 comments:

Anonymous said...

Yet FP languages have been around for at least 40 years as well. And I'm not sure if the economics of retraining engineers is the real reason behind FP's low mileage in the real world. After all, as I understand, FP is taught to undergraduates (admittedly not as much as OOP and good ole iterative programming).

Could it be that iterative programming is more 'natural' and akin to the linear problem-solving approach of the human mind? Oftentimes, writing a program is like reproducing the logic within one's mind and having the computer do it faster, better and with no mistakes (bugs are the programmer's mistake, not the program's)

OOP, on the other hand, is also rather natural - the modelling of how things work in the real world.

Any paradigm can be abused of course. I have seen classes made to do things that don't feel very object-oriented. That's again the fault of an ill-disciplined engineer, not the paradigm's. (Sometimes it is tempting, isn't it? To write code that "gets the job done". It'll only be used once anyway, the thinking goes... Good luck debugging!)

I haven't tried FP myself, although many years ago I did download a Haskell compiler. I guess the learning curve of FP languages is pretty steep, given that the paradigm is more mathematical than logical. A 6-year-old can program a LOGO turtle, but I doubt his grasp of lambda calculus.

VB6 isn't a toy language. It's probably to the VB family what Win2K was to the Windows family. In any case, I really don't think VB6 has higher order functions. Haha, but you could of course code a little handler yourself.. It should be easy to do that.

Using FP principles in non-FP languages.. I guess one issue I can think of is that the compiled code might not be optimised. (as compared to FP code compiled by FP compiler)


I disagree with the notion that FP brings salvation to common woes. Ill-disciplined software engineers will produce inconsiderate unreadable source, no matter what language or paradigm they use. An excellent engineer will write beautiful code no matter what too. A bad pianist sounds bad on a Steinway, but a good one sounds good on a toy piano.

It's the programmer, not the language.

Anonymous said...

wow! tt's a very long comment! :) but i think part of my concern is that writing a programming language, for all its technicality, is in the end WRITING. and where there's writing, there's bound to be different writing styles.

Functional style, imperative style, argumentative style, logical style, etc.

But the thing here is that different problem-sets call for different styles. Some styles are better suited.... I mean, if you're writing a technical report, you would prefer to use a technical style, because it communicates more concisely and clearly than a novel-writing style.

I think programming's still in its infancy in that sense. In NUS, we learn to use an imperative language in an imperative style, and then apply it blanket-style to everything we see.

However, a style is different from a language. It's just that imperative languages make it easier to write in an imperative style and ditto for functional. But we haven't learnt to combine functional style and imperative style using one high-level Turing-complete language yet.

Anonymous said...

Yes, different problem sets are best solved by different styles, and consequently require different languages. Imperative languages for imperative style, functional for functional.

However, I doubt there to be much to gain from using languages for what they were not designed for. i.e., when you need to use FP, use a FP language. If you need to use FP in a project using mostly imperative language, perhaps use libraries?

The languages might be Turing-complete, but arm-wringing them to do unfamiliar things might not be the best thing to do. They might be able to do everything, but they were made to do only certain things well.

btw, I'm seriously learning Ruby (on Rails) now.. :P

Anonymous said...

interestingly, Python is a mixed language.. you can do the same things 2 ways in Python, imperative or functional. i.e. It's a language designed with objectives of accommodating both.