The Principle of the Procrustean Bed in Programming

The software world of today has evolved to the point where the number and variations of programming languages are so large that it's impossible for someone to know even their names, let alone their features. I've recently found a site, www.99-bottles-of-beer.net, that provides solution to a program that prints a song about bottles of beer in 721 programming languages and variations. And that's a quite big number. What happens with the large majority of programmers is that they know, more or less, several programming languages and try to adapt all the rest to fit their programming customs and routines, even by breaking the conventions of a language or creating the false impression of something that isn't there. It's a Procrustean bed of programming.

So who was this man, Procrustes? He was a bandit named Damastes who lived near Eleusis in Attica, the territory of Athens in ancient Greece, and was later called Procrustes, which in old Greek means "the stretcher." He kept a house by the side of a road and offered hospitality to people traveling the roads, inviting them to dinner and to rest over the night in a special bed of iron, which, he said, had the special property of fitting the exact length of whoever lay down upon it. But there was a catch, because as soon as the person lay down on the bed, Procrustes began to stretch the person if he/she was too short to fit the bed, until he/she died, or cut off his/her legs if he/she was too tall.

Something similar happens today with many programmers. Object-oriented techniques are the ones most used today, so I will focus on object-oriented languages and examples. Many programmers know several largely used object-oriented languages, such as C++, Java, or C#. Many things can be done by using each of these languages in different ways; sometimes these tasks are easier with one language abd harder with another. Some things can only be achieved by using a particular programming language. The problem appears when people, instead of trying to adapt to one language, are working on altering that language to meet their preferences. Languages, like people, are different. Forcing a little bit the comparison, I would say that each programming language has its own personality and that should be respected. The power of software developing lies in the variety of programming languages.

One example I would like to tackle is provided in an article called Using Interfaces in C++ by Jose Lamas Rios. In this article, Mr. Rios proposes a way of using interfaces in C++. With all due respect, I strongly disagree with the approach. There is a catch in this title, because though interfaces are supported by Java, C#, and VB.NET (just to name a few languages), they are not supported by C++. In C++, there is no such thing as interfaces. However, there is an equivalent: abstract classes. Interfaces and abstract classes are used to achieve the same goals as different language-specific approaches. What the author proposes is creating several macros later to be used to apparently implement interfaces. Besides the fact of disguising the C++ keywords class and public as interface and implements, which has the purpose of turning the C++ syntax to the Java-side, the use of those macros is by no means error-proof and does not create a Java-like interface. All they do is create a C++ abstract class. The only good point is enforcing the declaration of a virtual destructor for the class, but that's the only point in it, and it's not a strong one. The method is tautological, it doesn't bring anything new to C++. Moreover, the programmer still has to follow standard C++ rules.

#define Interface class

#define DeclareInterface(name) Interface name { \
          public: \
          virtual ~name() {}

#define DeclareBasedInterface(name, base) class name : public base { \
          public: \
          virtual ~name() {}

#define EndInterface };

#define implements public

DeclareInterface(IFoo)
   virtual int FooSomething() const = 0;
   virtual void FooAction() = 0;
EndInterface

class Foo: Implements IFoo
{
   virtual int FooSomething() const {...}
   virtual void FooAction() {...}
};

In using such a construction, the programmer must:

  • Make sure all methods are declared virtual; moreover, they all should be declared as pure virtual methods (=0);
  • Make sure no data is declared for the interface because they are supposed to be just a contract that expresses behavior, but does not provide functionality of any kind;
  • Not derive interfaces from anything else but another interfaces.

So, C++ programmers still have to play by the standard C++ rules. Why do this if it doesn't bring something new? Using macros in this way reduces readability. Software needs to be maintained, new features added, old bugs fixed, Often, the members of the team that developed the software make the changes, sometimes a totally different team is given the task of maintaining some piece of software. When someone sees such a construction, like the one listed above (DeclareInterface \ EndInterface, implements IFoo), he/she may have some problems understanding what it's all about. Using non-standard methods in any commercial software has an important impact on the maintainability, and should be carefully avoided. Then, on the other hand, one rebel member of a team may dislike something, and decide to #undef and re-#define them in several files, creating even more confusion to the maintenance team.

So why go to so much trouble to create the false impression of interfaces in C++? I frankly see no good point in it. Because macros are expanded at pre-compile, we would just end up with a class. So, using the standard way of declaring would be much better.

Another example that I will consider comes from the C++ (or Java) programmers who start writing .NET applications, whether it is C# or VB.NET, and I have to admit that I was doing it too in the beginning. C++ programmers who follow the heuristic that says all class member data should be private and have Get/Set accessors use the same style in .NET. The problem is that .NET promotes the use of properties that allow clients to access class state as if they were accessing member fields directly, while actually implementing that access through a class method. Properties appear to be member variables even though they are implemented as methods. In C#, get and set properties are compiled into get_XXX and set_XXX methods, which is their representation in MSIL. However, simple properties are inlined by the JIT compiler, which means there is no difference in performance between accessing a property and a field.

Without getting too much into properties' technical details, the following examples are just not the C# way.

class foo
{
   private int data = 0;

   public int GetData() {return data;}
   public void SetData(int val) { data = val;}
}  

This is the C++ style applied to C#. With such a construction, if one wants to increment the data of foo, he must do something like this:

foo theFoo = new foo();
theFoo.SetData(theFoo.GetData() + 1);

In C#, one should use a property whenever he/she feels the need to add a Get or Set method.

class foo
{
   private int data;

   public int Data {
       get {return data;}
       set {data = value;}
   }
}

Property Data allows the clients of class foo to access the class' state as if they were accessing member fields directly. Instead, data is hidden and a single entry point for reading or writing it is provided. This conciliates both the clients who would like to avoid constructions like the one above, and the class designer who wants to hide the internal state of the class. For the given example, one now can simply increment data in natural way:

foo theFoo = new foo();
theFoo.Data += 1;

The last point I would like to express in this article is about the mixture of naming conventions and coding style. Java programmers used to prefix the fields of a class with an underscore ('_') to distinguish them from other variables.

class foo {
   private int _data = 0;

   public void setData(int data) { _data = data; }
}

When a Java programmer does that in C++, the compiler may have a problem because the C++ standard specifies that everything that starts with an underscore is reserved for the compiler implementation (paragraph 17.4.3.1.2). In C++, one should never prefix the names with '_'. This is an example that shows how mixing coding styles can get you into trouble.

Furthermore, to ensure good readability of the code, naming conventions should be used with respect for each language. C++ has its own coding style and naming convention, just like Java or C# have their own. Enforcing styles, features, and notations from one to another doesn't do any good, especially to the programmers less familiar to that language (whichever it may be). Sticking to the language specifics, rules, and standards is the right thing to do. Programming language features should not be stretched on Procrustes' bed.

The country in which you live is governed by a set of laws that all its citizens must follow. If you visit another country, whatever you do on that foreign soil is judged by that country's laws. You cannot say that you didn't know it, or that in your country the rules are different. Nobody cares. You can't just #define the rules to fit your needs. I believe the parallel is good enough for the purpose of this article. Follow the language features and rules, don't break them, and don't fake them. You only lose when you do that.

If you wonder what happened to Procrustes in the end, well, ironically, he was killed on his own bed by Theseus. So, make sure that whatever you do won't turn against you sooner or later.

References



About the Author

Marius Bancila

Marius Bancila is a Microsoft MVP for VC++. He works as a software developer for a Norwegian-based company. He is mainly focused on building desktop applications with MFC and VC#. He keeps a blog at www.mariusbancila.ro/blog, focused on Windows programming. He is the co-founder of codexpert.ro, a community for Romanian C++/VC++ programmers.