Compile Time Reflection

Compile-time reflection.

It sounds pretty cool, but what is it and how is it helpful?

I’ve been working on a project that’s been getting pretty big, and I wish I had come across this sooner.

Reflection is a method of code introspection, allowing for code to modify it’s own data structures. It sounds complicated, but it’s actually a pretty easy concept. If you’ve used python before, it’s similar to calling `dir(self)` in an object, to see what contents an object has. It’s main use is to see what data is contained within your object, and programmatically handle that data.

To emulate this ability, we can define an object’s data as a higher-order macro, similar to a Smart Enumeration. This being a macro means that we won’t be seeing any sort of run-time impact, but allows us to write code that leverages this macro to let us handle an object’s data without explicitly handling each and every data member. This is a pretty good thing, since it means our code will be more resilient, and error proof.

I know that sounds odd. Macros are bad and break everything, right? That’s the usual argument I hear against macros from my peers, but consider this – A macro can never make a spelling mistake. A macro will never have to check to make sure it’s processing each data member. If a data member is added to a class, the macro wont forget to process it.

That’s enough proselytizing from me, I’ll show you the code now:

The Code

I think that using macros like this is a fantastic idea. It’s been a big help to me, and makes additions to the code base very easy. The one big trade-off being made is that there’s no way to only select parts of the data; it’s handle everything or nothing, right?

Luckily, template functions to the rescue! Inline functions are similar to macros, in the sense that they aren’t functions that are called by the actual code. Instead, they are expanded in place when they are called.

We can take advantage of this using template specialization. We declare a template which does no work at all, then specializations for each data type we want to do work with. This will result in the code first being expanded to be applied to all our data, then the templates being expanded. Our end result: the we have code that will be applied to each and every data member, but can selectively be applied to certain data types.

Here’s a simple example of what I mean:

I know macro’s can be scary, but I feel that it’s actually in better practice to write your code in this way. Sure, it’s less explicit, and that’s scary to all programmers, but I feel it can be a powerful tool in the right hands.

Leave a Reply

Your email address will not be published. Required fields are marked *