Friday, September 02, 2005

The Problems with C++

Don't get me wrong, I think C++ was great back in the day. I simply don't think it's the most productive language to program in these days. The following summarizes my thoughts on what is wrong with with C++.

Threads and Network I/O
For many years now, whether you are doing server-side, client-side or embedded dev, you need two fundamental support elements from the programming environment: threads and network I/O. C++ has had neither of these. For reasons unknown to me, the C++ standards committee thought these features should be something left for non-standard libraries to implement. Perhaps this was due to the fact that historically many operating systems did not support these critical features (well maybe only a few did not). This has not been true for a very long time. I think that C++ not directly supporting threading or networking has been a huge /dev/null for productivity since you must either roll your own library or find some non-standard library that may not be available for all the platforms you need to support.

Portability
Historically speaking, C is portable (if you know what you are doing), C++ is not. Keep in mind I said historically. C++ portability was horrible until a few years ago. Yes, I said a few as in three (it's 2005 at the time of this writing). I feel that this is not the fault of C++ as a language. Compiler support of the draft standard varied wildly. Things only got better a few years ago because compiler vendors finally caught up with the standards ratified in 1998. Even the beloved gcc did not fully support C++ until relatively recently. Compared to other compilers, gcc was way behind in C++ support for quite some time. The current incarnations of the GNU C/C++ runtime libraries still treat multithreaded C++ as a second class citizen. I have been bald for many years. Perhaps some of this is due to spending long hours trying to work around thread termination bugs in C++ runtime libraries. I don't mean to pick on GNU code...Sun's Forte/Workshop compiler was complete garbage for anything other than trivial C++ until around 2002. Microsoft's C++ compiler did better in the area of standards compliance, but it still had some severe bugs, in particular some show stoppers in its STL implementation. You would typically not see them unless you were running under load on a multiprocessor system. These severe problems were corrected only 2 years ago! Microsoft never seemed to care, their internal C++ code was using ATL. STL implied portability...perish the thought.

STL is Great, but...
It's based on C++ templates. This is its greatest strength and weakness. STL was a huge productivity boost when compared with writing code in straight C. However, you could never safely expose STL in public interfaces, simply because they were templates, generated at compile time. Any change to a template implementation requires a complete rebuild of all clients using the interface. Furthermore, it requires that all clients be built using the same version of STL. In distributed systems and integrations with third parties, this is highly undesirable and sometimes not feasible. You can work around this problem by not exposing templates in your interfaces and employ the bridge pattern. This is a lot of tedious work however. Templates are very powerful and useful, but they must be used with care when designing library interfaces. If the export keyword was ever implemented by compiler vendors, most of this situation might be resolved. I don't think the standard ever mandated it.

Name Mangling was Never Standardized
Every compiler vendor creates proprietary encodings of method names to support overloading and namespaces. Because of this, a shared .so or .dll built with one compiler cannot be used by another compiler. Couple this with the fact that STL cannot be safely exposed in your library interfaces and you now have serious problems when needing to interact with third-party code. That is of course unless everyone is using the same compiler and STL implementation.

Standard Runtime Never Provided a General Purpose Smart Pointer
Yes, there is std::auto_ptr, but this is generally useful only for exception safety. You can't use it in STL containers. I assume C++ never defined a standard smart pointer as part of the standard library since it did not want to deal with threading issues? Writing a good, robust, inheritance-friendly, reentrant smart pointer implementation is not trivial. This should have been standardized years ago. Disciplined use of smart pointers in C++ code can eliminate virtually all stability problems due to memory leaks and heap corruption. Smart pointers are also critical for effective use of STL containers in multithreaded apps. In the absence of garbage collection, the smart pointer is critical.

Future Directions
I read recently on slashdot that a new C++ spec is in the works. Although I have not seen the draft version, the areas that Stroustrup commented on seemed to address some of the items I have mentioned here. It's probably too little, too late however. I think many areas of the software industry have long since migrated to platforms such as Java and .Net and various other programming languages. Perhaps platform is the key term here. I don't think the designers and maintainers of the spec ever wanted C++ to become a platform in the sense that Java and .Net are. I should probably read Stroustrup's book on the design of C++. This would probably give me a historical perspective on why C++ is what it is.