The Skeptical Methodologist

Software, Rants and Management

C++ Templated Namespaces

A neat trick you can do with templating is to create a templated namespace – i.e., a module/namespace that is bound at compile time rather than design time.  The interesting uses of these things come not from creating them, as they’re trivial (mostly a typedef), but rather any class expecting one as one of it’s template parameters.  It opens up what might be called “Context Oriented Programming” – a kind of aspect-orientation, monkey patching and structural typing package all wrapped up in one.

With the coming of C++0x concepts, this type of templating will become much easier.  We will no longer have to define our classes in terms of what libraries they require, but instead what types they require, and any and all dependencies will more or less go the way of the dinosaur in truly generic programming.

For example, here’s the templated namespace idiom:

template<class IntType, class FloatType, class ThreadType, class MemoryModelType>

struct TemplatedNamespace {

typedef IntType MyIntType;

typedef FloatType MyFloatType;

typedef ThreadType MyThreadtype;

typedef MemoryModelType MyMemorymodelType;

};

Pretty trivial.  Now, it’s use:

template<class ANamespace>

class UserClass {

ANamespace::MyIntType foo(ANamspace::MyIntType x){

ANamespace::MyThreadType::lock _lock();

return 2 + x;

}

};

A little wordy, but as you can see, we just wrote a class that doesn’t know what threading model it’s using, doesn’t know what type of int it’s using, or anything else.  Then, when we want to use this class, we build the namespace we want to use…

typedef TemplatedNamespace<long long, double, PTHREAD, NEW_DELETE> myNamespace;

UserClass<myNamespace> x;

We bind what threading we want as the user, rather than the designer having to try and think how to accommodate us no mater what.  This is similar to policy-driven-development on steroids, as you can begin to remove any and all types from your code and move them up to requirements on your ‘context’, or some passed in templated namespace.  These requirements can be expressed and checked at compile time via the use of C++0x’s concepts.

As you can see, since a class only drawing types from it’s ‘context’ rather than from any global types, we, the user, have very strict control over it.  We can pass in mock types a la dependency injection, as long as we meet the requirements as spelled out in any concepts the class uses.  We can also muck around AOP style with types that the original designer never meant to be overloaded or switched out.  Again, as long as we meet the concepts, the class should work (your mileage may vary).

Making a non-thread safe class into a threadsafe one simply replaces the various types that there should be threadsafe versions of.  Now a class doesn’t even know it’s threadsafe, but it is.  Similar to Python’s monkey patching (or duck punching), simply having types that meet the structural typing demands of concepts will work, meaning maintaining code can be as simple as switching out different types rather than going in and finding all the hidden dependencies that must now be changed.

Plus, it gives you a very refreshing feeling looking up at the top of your class and not seeing a single #include there.

Obviously this approach is wordy as hell, and like everything in C++, we feel like we’re fighting the system to do what we want.  But this approach also affords us a great deal of extensibility, maintainability and generic power to reuse different classes and code by simply changing the ‘context’, or namespace, it uses to find all of it’s types.  And with the upcoming C++0x concepts, it will aid in design because it will force us to think about our bare assumptions of what we expect our types to do, much like classic Design-By-Contract forces us to think about what our instantiations of those types might do.

I have a feeling we’ll all be seeing more and more of this type of truly generic programming 😉

Advertisements

September 21, 2008 Posted by | C++, Software Design | , , | Leave a comment

Doing the simplest thing that can possibly work considered harmful

I’m not sure if there’s a blogger out there that hasn’t written a “Considered Harmful” blog.  If you go back to the original article by Dijkstra, he never comes out and completely condemns GOTO’s but rather advocates capturing popular GOTO patterns and using those in “Structured Programming”.  I.e., loops, ifs and switches.  We still have reasons to pepper our code with GOTO’s in some cases, although following the rule that the use of a GOTO is either a) bad form and there’s a better way or b) bad form and there ought to be a better way, has granted us some of the more rich control structures in our high level languages.  Exception handling is probably the more recent advancement.  Anywho, enough with history.  I just thought it’s particularly humorous to use the phrase “considered harmful” with “simplest thing that can work” that’s all.

TDD advocates a method that you test first, then code up the “simplest thing that can possibly work” until the test passes, refactor and repeat.  TDD also happens to be a pretty damned effective method of producing code quickly and easily, as well as a huge pile of unit tests that make refactoring a breeze and aid in ensuring the quality of your code.  As I said in Unit Tests as a Negative, unit tests and the tests that TDD pushes you to create also serve as an excellent specification and documentation of your code – each and every one of them are contracts, enforced each test cycle, that explain “When my code gets a, it returns b.  Always.”

I can see the attraction to the “simplest thing that can possibly work” mentality.  Indeed, many of the problems we arrive at in software come from over-engineering a solution.  But blindly following the simplest thing, including the KISS principle, can lead to tragically comical under-engineering.  I’m reminded of a post from months ago where a TDD advocate attempted to develop a Sodoku solver using test driven methods.  It was pretty painful to watch.

The problem he ran into is that the main problem in software design is and always has been: How do we define the problem?  The problem is the problem.  When we can specify the problem well, and understand it, generally speaking there are always algorithms and data structures to solve it completely and elegantly.  It’s when we cannot specify the problem that we run into boundary errors and extensibility issues.  TDD is a very effective way to explore a problem domain one step at a time, when it’s unfamiliar.  Unfortunately, the problem of solving a Sodoku has an already well defined, elegant algorithmic solution.  There’s no reason to plod away step by step using TDD to explore it.  Moreover, TDD is one of many methods of problem domain exploration.  It gets points for probably being one of the most general, and applicable to any sub domain, but certainly gets points taken away in this case as it’s particularly bad at solving a mathematical problem.

In our Calculus courses, we didn’t spend all day making sure an equation worked when x = 1, then x = 2, then x = 3.  No, we instead explored a few examples, then attempted to algebraically generalize the solution in a proof.  Likewise, TDD can help you explore a domain, but too much emphasis might be given on the KISS regimen and too little on the refactor.  Just like our normal generalization ‘instinct’, if we’ve done something three times, it’s time to generalize it.  Likewise, three tests for any problem with a fundamentally algorithmic solution should give us enough ‘exploration’ to allow us to put our computer scientist hats on and provide a robust algorithm + data structure solution.

Not everything turns into an algorithm, obviously, we have message forwarding code, simple switches and our object structures.  TDD works here too, but you can’t always generalize.  However, the hardest things to test to prove an absence of defects also tend to be the ones easiest to abstract into a mathematical problem.  Red-Black trees have certain characteristics about them that have been proved logically.  Once we identify a problem as one that a Red-Black tree solves, the only testing we need to do is to ensure we didn’t screw up the implementation of the Red-Black tree.  We don’t need to keep testing for new inputs and outputs once we’ve taken an established solution to a problem, and frequently, TDD helps us find those solutions.

So while the first cycle of testing, using the KISS approach might work, frequently we need to always keep our trusty old computer scientist hats at the ready and, upon having a few examples/use cases/tests on how something should work, design the proper algorithm not just to satisfy the use cases.  In other words, abandoning the “simplest thing that can possibly work” for another methodologist cliche, “over-generalization is the root of all evil” (apparently there are two roots) might be a more effective way to utilize TDD.  Generalizing a solution over it’s variable inputs is one thing, but generalizing a solution over it’s types, functors, uses, policies, etc… is quite another.  One provides for more robust code as there is usually a ‘known’ proper, elegant solution.  The other makes code reuse much easier – however, it makes no sense when you only use your code once and can frequently send us down rabbit holes.

The elegant solution to a problem usually is a mathematical one, but it may not be the simplest.  Don’t confuse mathematical generalization with software reuse generalization as it might make you spend about 100x more manhours on that Sodoku solver than you needed to.

September 5, 2008 Posted by | Testing | , , | Leave a comment