Last week, I was working with a C++ team and they needed some testing help so I pulled out my bag of tricks. I showed them how they could make their code more testable by externalizing object creation and adding constructor parameters. They were a little shocked that I would add constructor parameters just to make code testable, so I asked whether they’d ever heard of dependency injection (DI). My question was met with silence, but frankly I expected it. In my experience, few people in the C++ community seem to know about dependency injection. Part of this is understandable. C++ has been growing away from Java for the last seven or eight years. There used to be a rather large overlap between C++ and Java programmers, but that’s changed. The Java community has spent a great deal of time developing frameworks and tooling to advance their practice, but tooling is difficult in C++ so that community has been spending a great deal of time pushing templates as far as they’ll go.

I was talking to Scott Meyers at a conference earlier this year and he said that he felt that the real fork in the road was ease of parsing and tractability of analysis; that C++ was developed before people realized just how valuable those attributes were in a language, and as a result, the things that people do with reflection and tooling in Java are now attempted with template meta-programming because it seems like the easiest avenue. It doesn’t look all that easy from where I sit, but it does look like a committed course of action. The C++ and OO communities don’t seem to have much in common any more in the solution space, but they do have some common problems.

Testability is a tough taskmaster. It’s hard to write code that is easily testable unless you’re very diligent. When we work in statically typed languages, code is coupled by default. If a class uses another class, you have a compile-time dependency. C++ does have a sneaky way out of this problem. Templates are essentially un-typed so you do have some leverage before they are all instantiated to type-safe code, but regardless, testability is hard. If a class of yours uses vendor software that you can’t really run in your test environment, well, you need an adapter to mock it out. If you didn’t build one in, you’re left with the task of refactoring one in.

In the Java community, dependency injection has evolved as a way to solve this problem. The core idea of dependency injection is simple: object creation is a separate concern. If you push object creation into a separate area: an über-factory, you can make your code more flexible and more testable. Most descriptions of DI dwell on XML configuration, but it’s really simpler than that. Essentially, a DI system has a big bag of types and you go to that bag (factory) and tell it to make you an object of a particular type. The bag looks at the types and sees if it can create the object you want. It uses reflection to examine constructor arguments, setters on classes, etc. If it finds that it can, it will give you the object you asked for. If you want an instance set up for testing, you alter the types in the bag.

C++ makes this a bit difficult. There’s no general way to determine the arity or arguments of a constructor at compile-time so that standard tricks for mimicking reflection with templates don’t work. There may be a way to do setter-based injection, using some of Andrei Alexandrescu’s hierarchy generation techniques, but I’m not sure yet.

In any case, it seems that to do DI in C++, you have to place constraints on the classes you create.. you have to make them inherit from some other class, use macro preregistration or a metaobject library. The one C++ DI framework I've heard of, QtIocContainer, seems to bring along some of those constraints. Maybe they are inevitable.

The thing that I do know is that it would be useful to have more awareness of DI in the C++ community. I may be overestimating it, after all, the C++ community has not had nearly as many widespread, crippled vendor APIs hoisted upon them.. APIs which make testing a real bear, but I’ve seen a few, and I suspect that DI could help.