Cyclic Dependencies: Clean the Up!

September 14th, 2008

Cyclic dependencies are a challenge for any build system and code to handle. But I you look closely at cyclic dependencies, in most if not all cases they are a structural problem and not a technical problem. Cyclic dependencies indicate in most cases either that two modules belong together or one module implements two tasks.

Let’s take a projcect I am currently working on. There are two modules, the Interpester and the Object Manager, both are cyclic dependent. The Interpreter implements a virtual machine. The Object Manager implementes object serialisation and low level buissness logic. The basic contollflow is as follows: Object Manager calls Interpreter to evaluate some value and to do this the Interpreter calls back into the Object Manager get values to a given object.

If you read the above paragraph cloasly you will notice that the Object Manager implements “object serialisation and low level buissness logic”. Well as you can see there are two tasks that can and should be split in two seperate modules. If they are split in three modules there are no cyclic denendencies.

Tools of the Trade - Know Them

July 16th, 2008

In my dally work I am astounded as how little your average programmer or rather software engineer knows about the common tools of the trade.

Under some of the books I own is:

  • Pragmatic Programmer - Andrew Hunt and David Thomas
  • Mythical Man Month - Fred Brooks
  • Design Patterns - Erich Gama et al.
  • Test Driven Design - Kent Beck

And thew discuss a number of issues and tools every programmer should know1).

Can you imagine that, as far as I have seen, at least 50% did not know about unit testing or design patterns?! I am not saying that you need to use them all the time, which is absolute folly. But not even knowing that they exist is a sin.

What is even more depressing is that the younger generation should and probably had these subjects mentioned during their university courses. How can people not take their job seriously and thus make their job herder and more turblesome.

Big Changes, Step by Step

April 21st, 2008

Working with legacy code can be frustrating and often you might want to scrap everything and rewrite it. Many projects try this and in almost all cases they fail at it. They have a really hard time, because the problem at hand was not as simple as it seemed.

What people ignore is the fact that the code contains a large number of little bits of knowledge, quicks of the system that are not obvious. This knowledge was gained though long years of maintenance and the inherent problem is that this knowledge gets lost on a rewrite.

On the other hand, legacy code can become a maintenance nightmare. Something has to be done to improve code quality, rejuvenate the code and thus reduce the maintenance burden.

The solution is to make many small changes and improve the code quality day by day. By refactoring the existing code the knowledge within the code is not lost and you have a running system all the time.

The Beauty of C++ Cast Operators

April 19th, 2008

Many criticize the C++ explicit cast operators. Common points of critique is that they are clumsy or redundant. But I believe that most people who are criticizing the cast operators did not understand what the point is about them.

A Bit of Theory

If you do not know what I am talking about, the explicit cast operators are static_cast, reinterpret_cast, dynamic_cast and const_cast. Every cast operator has its own use, lets see what it is.

The const_cast operator is there to add or remove const or volatile. It is not often used, but some cases where you are working with “broken” third party libraries, this operator can be required.

The dynamic_cast is used then casting polymorphic objects. It is a safe cast since it only returns a useful result when the cast is successful. This is done with the help of runtime type checking and can give a slight performance hit.

The reinterpret_cast is used when you blindly want to map the bit pattern from one type into the other. This was never possible with C casts.

The static_cast is the simplest cast there is. It is almost the analogue to the C cast, except for removing or adding const or volatile. It can do the same things as dynamic_cast only the safety disabled.

Casts are Evil

Although this bold statement is slightly exaggerated, if you have casts in your code there is a good chance that there is a flaw in your design. Casts mean that you convert from one type into the other, why is the data not the the format you need it?

It is true that you need casts when you connect two pieces of software together, such as adding some third party software to yours. But even here the requirement to convert from one format to the other is a flaw, even though it might be only a minor flaw.

Every time you cast data can be lost or potentially turn out to nonsense. The new cast operators make the cast clearly visible and debugging often becomes easier, since potential places of data loss are clearly marked.

Not Really Awkward

The cast operator look like functions and if you really think about it they are not as awkward as C casts. In addition concepts such as lexical_cast or any_cast where easily accepted the syntax closely follows the “real” C++ casts.

If you ever accessed a member with a C cast, compare the two alternatives:

// C cast
((MyType*)value)->some_member;

// C++ cast
dynamic_cast<MyType*>(value)->some_member;

Not that this code is good style, since the cast may fail. But the C++ cast does not need any odd parentheses and you can’t cast the result by mistake.

Separate Data and Algorithms

March 7th, 2008

At the beginning of every object oriented programming course you will learn that objects unite data and algorithms on that data. This is a naive view of object oriented design and can lead to strongly confusing designs.

It is true that with objects the “real” data is encapsulated within a object. But putting algorithms into the object creates a strong coupling of data and algorithms.

The solution is to use a true and tried paradigm and separate data from the algorithm.

Does that mean that we should ditch objects completely? No, of course not. You create data objects and behavioral objects.

Data objects are objects that have a defined interface with a number of data items that can be queried or modified. It dos not mean that every get and set method is directly associated to one attribute of the object. Some elements only exist as values computed on the fly.

Behavioral objects on the other hand encapsulate algorithms and behavior. These objects then operate on the data objects. This creates a simple and understandable design where it is clear what goes where. In addition this opens the door for behavior and algorithms unthought of as the data object was conceived.

std::tstring

February 18th, 2008

If you are using Microsoft Visual Studio the use of the Microsoft Foundation Clases (MFC) is often seen as a must. But MFC is a relative large library and many modules don’t use much of it. There are cases where the only piece of MFC is CString. But linking against MFC just for CString is superfluous.

Since the standard C++ library is always bundled with every compiled program the use of std::string and std::wstring is a good alternative. Conversion from and to CString is trivial, if you know the current settings.

The problem is that many functions defined by the WinAPI and MFC are dependent if Unicode is used or not. Depending on the settings either char or wchar_t us used. So code is independent to this setting TCHAR can be used. It will then be defined to the one or the other.

In the one case you can plainly convert to std::string in the other std::wstring. But which do you use in your code. This gets worse if you receive and return the strings; character set conversion is out of the question.

The Microsoft Solution

If you read about this in the Microsoft Developer Network (MSDN) you get a plain solution: Use the preprocessor.

#ifdef _UNICODE
#define tstring wstring
#else
#define tstring string
#endif

This solution follows the same as many proposed by Microsoft. But if you give me a Euro for every #undef I needed to write in my code, bacause a macro from the WinAPI tainted my code, I would be rich.

Definition

Since we are programming C++, it is wise to solve the problem with the means of the language instead of the using a preprocessor hack. The definition of tstring follows the definition of string and wstring. tstring is a variant of the template basic_string with TCHAR. To add a little type safety and portability I defined tchar_t following the idea of wchar_t.

namespace std
{
    typedef TCHAR tchar_t;
    typedef basic_string<tchar_t> tstring;
}

tchar_t and tstring where defined in the namespace std, to show that it actually just is a special form of basic_string and fully compatible to other standard code.

Streams

Well now that you have your string class dependent on TCHAR, there is the problem of streams. Streams are also parameterized for char or wchar_t. But here the solution is straight forward. Define your own types based on ”basic_streamtype”

namespace std
{
    typedef basic_ios<tchar_t>              tios;
    typedef basic_streambuf<tchar_t>        tstreambuf;
    typedef basic_istream<tchar_t>          tistream;
    typedef basic_ostream<tchar_t>          tostream;
    typedef basic_iostream<tchar_t>         tiostream;
    typedef basic_stringbuf<tchar_t>        tstringbuf;
    typedef basic_istringstream<tchar_t>    tistringstream;
    typedef basic_ostringstream<tchar_t>    tostringstream;
    typedef basic_stringstream<tchar_t>     tstringstream;
    typedef basic_filebuf<tchar_t>          tfilebuf;
    typedef basic_ifstream<tchar_t>         tifstream;
    typedef basic_ofstream<tchar_t>         tofstream;
    typedef basic_fstream<tchar_t>          tfstream;
}

Conversion To and From CString

Conversion to and from CString, LPTCSTR or LPTSTR is plain simple. The most important aspect is that no character conversion is necessary.

Conversion from CString to std::tstring:

CString     cstr(_T("test"));
std::string std_str(cstr);

Conversion from std::tstring to CString:

std::string std_str(_T("test"));
CString     cstr(std_str.c_str());

Conclusion

Just because other modules use TCHAR, LPTSTR, LPTCSTR or CString does not mean you can’t use C++ standard classes. You only have to create your own variants.