What is *wrong* with the imperative programming? That’s the question that came up in a discussion where I was part; the dicussion group comprised of people from diverse software background and most of them has their lineage to C or C++. The points that came up during that discussion were well spread over the day to day activities of the programmers working in various types of projects.
Actually if you see from a distance it is absolutely ok to write a piece of code in your favorite imperative language, but if you take some time and code the software in your favorite functional programming language it feels and looks better; of course your choice of functional programming language has to be good.
Side effects make lot of problems while coding in imperative languages. Say you have a program that runs into several functions and as imperative language like C does not support higher order functions (in true sense) your functions are dependent on what we know as *GLOBAL VARIABLES*(to preserve the global state). Lets assume that you set an error flag if something has gone wrong in some function. As each function is interlinked in producer-consumer relationship with each other, once a function has done its job you have to see whether there is any error set or not. So your code will be sprinkled with codes like this:
i = fn1();
This is not only bad while typing but also an example how a programmer loose his ability to think. How? As our example goes if you do it in several files and several functions; one fine morning loose the intent to think what may go wrong in simple function which is just checking whether a file exists or not! And I can tell you this happens because this happened with me.
Other than this, think about the time that I spent error handling. People might say that this is because you are using a programming language which does not support better error handling mechanisms to help the programmer. I agree, but as we know the imperative programming languages will always depend on Hoare Logic, i.e. it will have the notion of pre and post conditions. If we see both the paradigms of programming (lambda calculi and Turing machines) depends on those conditions but pure functional programming does not have side effects as it does not change (although lisp programs can do that) the values of its parameter.
But when I code in lisp I know that if I need an output from one function to another I will using the first one as a higher order function to the later. Then the second function only need to know what it expected out of the calling function if something goes wrong in the higher function it can handle it then and there and end the execution flow gracefully. This brings me to next topic execution flow.
Execution flow: Where am I?
Yup! This is a nightmare for any programmer in the imperative programming world; a bunch of programmer I knew once wrote a simulation program for Intel 8085 microprocessor but after each cycle of execution they didn’t know from where the program exited. It used to exit with unhandled error each time in Windows. If you think who they were I can tell you I was in that group. It took us some effort to fill that gap.
Now you might say that boy that doesn’t happen in real world! Oh yes that does not happen but we always have way to complete the process and most of the time the process is return-return-return till you come to main and then do simple check up and clean up of your mess with memory and then die by returning 0. No problems with that but think that if an execution starts and you know from the first command line checking itself that the user has made a mistake but you still follow your way of closing after eating some good processor time.
But in lisp you can’t loose your track! Even if you want you can’t, simple. How? If you are creating a properly designed lisp code with functional style you will be calling functions on top of one another so it will go on till the boundary of your hardware! It may fail some times but you will not be loosing your track. Even in error without any extra effort from your side you will be getting messages like: “Debugger invoked on ….”! I say, it’s just cool.
LOC – Yeah the greatest enemy of code!
I think Steve has given enough reason in his post so I need not prove this. But yes if I look at my C code some times I cry! How much I have typed for so little. Take the famous, old and boring “Hello World” program. In C you have to type at least 5 lines. In lisp REPL it’s only “Hello World”. Even a fancy function will be 2 lines. So you save 60% of typing effort while working with “Hello world” program.
And as the saying goes with lazy programmer I feel good while I use my “TAB” key for auto complete in XEmacs.
It happens especially if you need to work with raw data. By the time I finish structure filling code in C, I bet will be able to complete a subset of other tasks like some parsing also.
The crux of the matter is doing more out of less. If this is not good enough for you rethink about becoming a programmer.
My first impression about C macros was, “Here is subject which I need to learn because I really do not know what is wrong with my code when I use them.” The best macro I have used in my C code:
# define PRINTLN printf(“\n”);
And believe me it worked wonderfully for me. People in that discussion never understood what I was talking about when I said “function returning macro” or “code writing macros”. Because they do not know what a power a macro can have if you are programming lisp.
(I can go on talking about macros but I should refrain as this is not a sub-topic but requires major effort and can span several posts.)