What is the right way to handle exceptions?

There are several ways to handle exceptions in a program. An exception, that is, a condition from which the program cannot recover locally, can be handled by checking the result of function, or using a try/catch mechanism (which can be simulated in C by a long jump).

Between these two extremes of the spectrum, a lot has been said and done. However, they represent not only technical options, but ways of thinking about how a program works.

The try/catch technique is currently well established; it is not the only option though. C programmers have always used return values as a way of expressing the status of the executing code.

The problem is that there is a lot of redundancy and inefficiency in the use of exceptions. To see this, consider two options from the many uses of exception based code: expected conditions and unexpected conditions.

Expected exceptions are the ones we know how to protect from. For example, it might be a memory exhaustion problem. In that case, we know where the issue is coming from, which means that it could be more economically handled using error codes.

Unexpected exceptions, on the other hand, are the ones that we don’t know how to recover from,  mostly corresponding to bugs on some combination of software/hardware.  Here, throwing an exception is useless, because while a bug is happening, the most you will get in terms of debugging information is a stack trace. On the other hand, a core dump generated by a language like C++ is much more informative –  it shows not only the location, but also the contents of memory at the time of the crash. Exceptions, though easy to program, don’t let a core dump happen, because by definition they need to call all the destructors (in C++ at least), and execute required catch and finally blocks.

Objections to Error Codes

The standard objection to error codes is that you have to check them at every use. This is not true, however: one can create “check an cleanup versions” of every major function that returns an error code. Then, on error, the code calls a clean up function that can do the required “destruction” of objects. One can even install handlers that take care of cleaning up specific modules.

In fact, production code in C++ that uses exceptions does something similar. Exception catching is frequently isolated in a few modules that do the right thing, instead of just  mindlessly receiving the exception and printing something.

What is best then?  Exceptions are certainly easier to use, but impose a run time penalty that cannot be avoided (and consider that C++ tried really hard).  Moreover, professional users know better than throwing and catching exceptions ad-hoc. So, the advantages in terms of functionality are really not clear.

A lot of production software in C++ doesn’t use exceptions (Chrome, for example). Exceptions are not reentrant in C++ (because of destructors). While in Java one cannot avoid them (built into the language), in C++ I believe one should think twice about using exceptions and the main way of handling error conditions.

What Makes a Good Programming Language?

What makes a good language? It depends on what you like in a programming language, of course. If you enjoy functional programming, you probably won’t be happy with Java. If you dislike managing memory, certainly you should avoid C. But there are some features that are shared by a large family of languages, and they make a good case of what might be good features for all of them.

Conciseness is a good case. There are extremes in conciseness that have been observed throughout the short history of computing. For example, it is hard to imagine something more terse then APL, or one of its modern equivalents, such as the J language.

On the other hand, the extreme verbose languages have always been among us. COBOL was predicated on the assumption that more was better — and it ended up that any reasonable COBOL program is machine generated.

I am the kind of person that likes to err on the side of terseness. In my mind, programming ideas are terse anyway; I am always trying to reduce algorithms to its simplest form. And when you learn a language well, it is better to read less than more — most professional programmers agree with this.

Another issue I have is with languages that don’t give you options when a common problem happens. Programming languages should be designed to be flexible, not the other way around — it is in the spirit of programming. For example, Java requires you to write code that is spread in as many directories as you can create. The designers of the language tied access to symbols to the directory where the symbol lives. This is the kind of thing that makes a language to look amateurish, even though there is a huge amount of work done in Java — every one has to bow down to a wrong and inflexible decision.

The other thing about inflexible languages is that they need tools to be used. The same way you need a code generator to use COBOL, you are required to use an IDE to generate boilerplate code in Java, as well as to navigate its complex tree of source directories. No wonder why the industry loves this kind of languages: between virtual machines and IDEs there is a huge market to be explored.

As for me, when I have a choice, I always try to avoid languages that make me repeat the same old mistakes. If you don’t have the ability to define a behavior directly in the programming language, then you are condemned to repeat the same mistakes (or at least required to protect against them in some way).

What to watch for in a Framework

Frameworks are created to make our lives simpler. They try to hide most of the complexity from an environment using layers of library code. In that way, users don’t need to worry about managing the lower level features of the environment. They should, instead, concentrate on the higher level functions (business logic) of their code.

With the increasing number of technologies that we have around us, there has also been an increase in the number of Frameworks — all of them trying to compete for attention.

In many cases, frameworks do a good job of hiding low level information from programmers. However, they also have a few problems of their own.

For example, when using a framework we are hiding some complexity, but also creating some additional levels of complexity that can become a major issue.

For example, consider web frameworks. There are hundreds to chose from (literally), but most of them are equivalent. They solve the issue of letting programmers create a web site quickly, by taking care of basic mechanisms, such as serving web content and accessing a relational database.

However, web frameworks also create its own particular language, that needs to be understood by developers before anything gets done. Also, although they make it easy to create simple websites, things may get complicated when less common features are required from the web site.

In the end, power users need to spends lots of time learning the ins and outs of a web framework. A high level of proficiency is necessary to achieve more complicated results.

In some extreme cases, the framework may get in the way between you and the intended result. This is where things stop being fun and become a nightmare.

To avoid such problems, there is a number of things that I consider before using a Framework:

Documentation: if you have to mess up with a framework, it needs at least to be well document. There is nothing more frustrating than trying to get something done and having no clue of how it can be achieved.

Reading the source code may sometimes be a solution, but it only works if you know what the source code is supposed to be doing. If you don’t know this, having the source code is not of great help.

Ability to reach for the lower level: what happens when you want something that has not been implemented in the framework? A possible solution is to reach for the lower level if that is necessary. Don’t use a framework that makes this very difficult. Sooner or later you will need additional functionality.

Extensibility: even though a framework may strive for completeness, there is always some feature that has not been suitably covered by its creators. In that situation, is it easier to extend what has been provided, or you have to start from scratch?

Availability: how many people are using this framework? A lot of users probably means that you will have a better time getting support. It will also be easier to find someone else to share experiences, or even use your expertise in somebody else’s projects.

Answering these questions may turn your decision to use a framework much easier. After all, if you do anything, don’t start using a framework just because it looks cool or it is easy to achieve some specific effect — the decision of what framework to use must be better informed, because it can deeply impact the future of your project.