mercredi 18 février 2009

Throw those error codes out

What to answer when asked to justify your use of exceptions:
  • It makes the main flow of the program obvious
  • It's the only sane way to signal an error from a constructor
  • It avoids partially constructed objects
  • You can't avoid them anyway
  • The information carried by exceptions is better structured than error codes
  • Error codes don't scale, exceptions do
It makes the main flow of the program obvious
When using exceptions, you don't need to check every single function call for error condition. This removes a lot of repetitive, useless code that gets in the way when trying to understand what is the first purpose of a single piece of code.

It's the only sane way to signal an error from a constructor
You could choose to only have useless constructors and init methods on every class... and you'd be wrong to do it. init methods are often the result of an inadequate error management strategy. More on that later, for now it should be clear that constructors don't have return values, and if you give a constructor an output parameter, you are in a fight against the language you can't win.

It avoids partially constructed objects
This one is huge! People underestimate it - big time. A good deal of what makes a class difficult to design & maintain is the number of states its instances can have. If any member of a class can be either constructed and non-initialized, constructed and initialized, constructed and partially initialized, constructed and uninitialized and , finally, destroyed.... what was I saying? Oh yeah, if any member can be in any one of those states, you are in trouble. You get destructors that are impossible to write, you have live objects everywhere in your system that are time bombs. Ever seen code like this?




if ( is_init() )
{
do_it();
}
else
{
return E_FAIL;
}


That means that the object can be in an invalid state. The class is not doing its job : the class's invariant is ill-defined. You don't get that when you use constructor with exceptions.

It all makes sense when you consider how members initialization/finalization works. First, members are destroyed in the reverse order of construction : it makes sense. When members are constructed {that's before the body of the parent's constructor begins its execution}, if the Nth member's constructor throws, the previous members {those that are fully constructed} will see their destructor called : it makes sense. If the Nth members fails, the destructor of the following members won't be called : that is very useful.

And memory leaks? If you have this :

my_object* obj = new my_object();


and if the constructor of my_object throws, the memory allocated by new will be freed automatically! No leak! :-) Of course, if would be a good idea to use some kind of smart pointer because if this object's constructor won't fail maybe something else will throw before the call to delete.

You can't avoid them anyway
new throws. The standard library throws. Boost throws. The world throws. Accept it. You not throwing does not spare you from writing exception-safe code.

The information carried by exceptions is better structured than error codes
It's easier to choose the right exception class when throwing than to structure error codes returned by functions. You will find tons of functions returning an int as an error code, I hope you will find a lot less functions throwing an int :-)

Error codes don't scale, exceptions do
Error code management implementation size grows with the number of functions called. Exception catching is pretty much O(1) and exception throwing implementation is proportional to the number of possible failed postconditions, I don't see how you could do better than that.

Shit happens. For the love of code, throw the shit out.

dimanche 15 février 2009

One possible path


VLAM will soon hire an intern. This brings a host of questions about cv selection, which school to choose, the interview process, etc. What interests me the most at this point is how to educate a junior programmer up to the point where we will be able to trust his code.

One possible path I think can work is the one displayed on the left.

Procedural

VLAM is a real-world software production environment and we need our programmers productive right-away. I find that even if functional programming has a definite mathematical beauty and simplicity, juniors don't get it right away. They do get that variables can refer to different values as the program is executed.

On a very practical note, we use 3rd party software that have very procedural interfaces. Procedural programming is the basis, the starting point and the common denominator. I hope I won't actually have to teach basic structs, unions, file handling, printf and C function pointers ; but if I have to, I'll try to get it out of the way right from the start.

Object

Inheritance, overloading, overriding, constructors, destructors - a junior coder has to master all of that before he can tackle exceptions (with of course exception-safe software design) and functional programming. Object-oriented programming is not a goal, but it is full of very usefull tools. Please, for the love of gods, don't stop here. Don't end up with "object-oriented programmers". Teach juniors patterns, so they can detect and factor them out in the future.

Key concepts :
  • The construction, allocation, destruction and deallocation of objects
  • Overloading, overriding
  • Multiple inheritance (and the diamond of death)
  • Patterns
Books to read :
  • The effective C++ series
  • Agile Software Development, Principles, Patterns, and Practices

Contracts, error handling and exceptions

I won't go on here about why you should use exceptions - that can be the subject of another post. Needless to say, proper error handling, asserts and exception safety is very important. Unfortunatly very few programmers in the real world are able to write code that won't leak or fail miserably when not everything goes as expected.

Key concepts :
  • RAII
  • asserts & contracts
  • try/catch
Books to read :
  • The exceptional C++ books
Functional

By this point, it should be clear to the new programmer that it's easier to write correct, extensible code when it's stateless. If C++ is your main tool, now is the time to fully understand how to use boost::function and boost::bind.

Key concepts :
  • Closures
  • Declarative-style programming
Books to read :
  • Structure and Interpretation of Computer Programs
Generic

This is a big one. Templates in C++, generics in Java and C#. They can be as painful as they can be useful. You absolutely need to cover object-oriented programming before, because you will need all the tools of classes to actually implement to opposite idea : the separation of algorithms from data structures.

Key concepts:
  • Runtime vs compile-time
  • SFINAE
  • Code generation
Books to read:
  • C++ Templates - The Complete Guide
  • On Lisp
  • Modern C++ Design
Scripting

Many would start with scripting, and yet I put it at the end. I don't mean that a junior programmer should wait to learn python or ruby until he masters C++ templates - quite the opposite. I think juniors should already know a scripting language before you hire them in the first place. I'm talking about the integration of scripting in applications.

After a programmer has suffered through C++ templates, once he understands what it take to write statically-typed reusable code, he is ready to bridge the gap between static and dynamic languages. Swig is no easy piece of cake, but if it allows you to write most of the code in a sane language, it's a small price to pay!

Key concepts:
  • Embedding
  • Foreign interfaces
  • Domain-specific languages
Any book suggestions?