Monday, September 24, 2007

Why Functional Languages Should Not Be Used for Safety-Critical Applications

All Functional Programming Articles

I Actually Like Functional Languages But With a Caveat

This may come as a surprise to my enemies in the functional programming community but I happen to like functional languages. Their power of expression cannot be denied. I especially like Mathematica, if for nothing else than its beauty alone. My bone of contention with FP proponents is not that FP is not useful, but that it should not be used for complex, real-time, safety-critical and automation-type systems. I believe that FP should be used mainly for solving mathematical functions for which it is ideally suited. I have used words like ‘crap’ and ‘abomination’ to characterize FP but that’s mostly for effect. It bothers me that FP proponents are championing functional languages (especially Erlang) as the solution for the parallel programming problem. It is not. Erlang is encouraging coarse-grain, inherently non-deterministic, thread-based parallelism at a time when the computer industry should be shooting for fine-grain deterministic parallelism, an essential requirement for safe and reliable software systems. I also want to draw attention to the fact that FP is not a software model. A functional language is mainly a specialized problem-solving tool that sits on top of an existing model which happens to be the algorithmic software model. As such, it inherits the principal drawback of algorithms, unreliability.

FP and Safety-Critical Applications

There is a real danger in thinking that FP even comes close to being a silver bullet for the software reliability problem. If it was, there would be no reason to advertise Erlang as a language for the construction of fault-tolerant concurrent software systems. Fault tolerance subsumes the likely presence of hidden faults, does it not? Note that I am not saying that there is anything wrong with fault tolerance, as long as we are talking about hardware faults. My problem is with software faults. They bother me. They do because I, unlike Joe Armstrong, the main inventor of Erlang, don’t think they are inevitable. The pundits may insist over and over that unreliability is an inherent characteristic of complex software systems but, from my standpoint, they are referring only to algorithmic software. There is no doubt in my mind that, should the computer industry decide to abandon its long sordid love affair with the algorithmic model and settles down with a nice, non-algorithmic, synchronous reactive model instead, the reliability and productivity crisis would simply vanish.

Finding and Resolving Data Dependencies

The irony of it all is that the very thing that FP gurus are railing against (the use of variables) turns out to be its Achilles’ heel. I understand their rationale. The use of variables introduces unwanted side effects that invariably lead to software failure. However, as I argued in my previous article, getting rid of variables is not the answer. Besides, FP does not really get rid of variables, it replaces them with functions and these keep their changing values on the stack. It just so happens that traditional variables are part of the solution to a vexing problem in software systems. I am talking about the discovery and resolution of data dependencies. Traditionally, this is done by the programmer but, and this is my main point, it does not have to be. It makes no difference whether or not one is using declarative or imperative languages, it is easy to miss dependencies in a complex software system. This is especially true if the programmer is in charge of maintaining a legacy system that he or she is not familiar with. Any addition or modification can potentially introduce an unwanted side effect.

Using Variables to Automatically Find and Resolve Data Dependencies

A data dependency exists whenever one part of a program depends on data changes occurring in another part. Keeping dependent objects up-to-date with the latest changes must be done in a timely fashion. For example, the movements of the mouse or the clicking of a button must be communicated immediately to every target program or module that needs them. What is nice about this is that we can run a simulation program that generates mouse clicks and movements without having to modify the target programs. This is an example of dependencies being resolved automatically in a reactive manner. Let me take it a bit further. Any time you write code to perform a comparison operation on a data item, a new data dependency is born. If you add new code that modifies the data but you forget to invoke the comparison operation in a timely manner, you have a situation where a part of the program is unaware of the change and continues to operate under a false assumption. Failure is bound to ensue. Like I said, this is a major problem when maintaining complex legacy systems. There is only one way to solve the problem and that is to adopt a non-algorithmic, reactive, synchronous software model and allow the use of variables. The idea is to associate every effector (operator) that changes a variable with every sensor (comparator) that may be affected by the change. This can be done automatically in a reactive system, eliminating the problem altogether. You can read the fine details elsewhere.

The FP Data Dependency Problem

The problem is that FP forbids the use of variables in functions and FP systems are not reactive. So the question is, how can FP automatically resolve data dependencies? Answer, it cannot. This is the reason, in my opinion, that FP is not suited for safety and mission-critical applications like avionics, air traffic control, power plant control, medical and financial systems, etc… In other words, use it at your own risk.

No comments: