Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When/Why ( if ever ) should i think about doing Generic Programming/Meta Programming

IMHO to me OOPS, design patterns make sense and i have been able to apply them practically.

But when it comes to "generic programming /meta programming" of the Modern C++ kind, i am left confused.

-- Is it a new programming/design paradigm ?

-- Is it just limited to "library development"? If not, What design/coding situations call for using meta programming/generic programming.

-- Does using templates mean i am doing generic programming?

I have googled a lot on this topic but do not grasp the BIG PICTURE fully. Also see this post.


After reading dicussions here under, up till now, I am sure ( might still not be correct):

a) Generic programming and meta programming are two different concepts.

like image 523
Aman Aggarwal Avatar asked Jun 11 '09 09:06

Aman Aggarwal


3 Answers

Metaprogramming is a pretty exotic topic. It's interesting to learn about, it's a powerful tool, and occasionally you might find it useful. But it'll never be the most often used tool in your toolbox. Sometimes, you might want your code to act on a range of unrelated types with different properties, and that's where metaprogramming comes in. With a bit of trickery, you can write an overload of a function that is only available if the argument type is integral, or if it is a pointer, or if it is either type X, Y, or Z (perhaps ignoring constness on Z).

It is essentially programming with types. Normally, your program can do things like take two numbers and produce a third number, or tell you whether a number satisfies some requirement. Metaprogramming can take two types and produce a third type, or tell you whether a type satisfies some requirement. And yes, it is probably mostly useful in library development. But then again, most code could be considered library code. You could say that everything outside your main() function is library code.

Usually, if you want to solve a problem through metaprogramming, you'll probably want to use the relevant boost libraries to do the heavy lifting. Boost.TypeTraits and of course Boost.Mpl can really simplify things for you. But it's not something you need to know, and it's not something you're likely to need very often.

Generic programming is related (and may in some cases use metaprogramming under the hood to become really generic, for example the standard library uses a touch of metaprogramming to turn raw pointers into valid iterators which is required for the "iterator" concept to be generic), but not entirely the same. And it is much more widely used.

Every time you instantiate a std::vector, you use generic programming. Every time you use a pair of iterators to process a sequence of values, you use generic programming. Generic programming is just the idea that your code should be as generic as possible, and should work regardless of what types are put into it. A std::vector doesn't require the contained type to implement a "ICanBeContained" interface (remember how Java requires everything to be derived from Object in order for it to be stored in a container class? Which means primitive types get boxed, and that we lose type safety. That's not generic, and it's a pointless restriction.)

The code to iterate over a sequence using iterators is generic, and works with any type of iterators, or even with plain pointers.

Generic programming is very widely useful, and can often to a large extent replace OOP. (see the above example. Why would I write a container that required the contained types to implement an interface, if I can avoid that limitation?)

Often, when you use interfaces in OOP, it is not to allow the type to change during runtime (although of course that happens from time to time too), but to allow you to swap in another type at compile-time (perhaps injecting a mock object during tests, rather than using the full-fledged implementation), or just to decouple two classes. Generic programming can do that, without having you do the tedious work of defining and maintaining the interface. In those cases, generic programming means you have to write and maintain less code, and you get better performance and better type-safety. So yes, you should definitely feel at home with generic programming. C++ isn't a very good OOP language. If you want to stick strictly with OOP, you should switch to Java or another more more OOP-fixated language. C++ allows you to write OO code, but it's often not the best solution. There's a reason why almost the entire standard library relies on generic programming, rather than OOP. There is very little inheritance or polymorphism in the standard library. They didn't need it, and the code became simpler to use and more powerful without it.

And to answer your other questions, yes, Generic programming is pretty much a separate paradigm. Template metaprogramming is not. It is a fairly specific technique for manipulating the type system, and is very good at solving a small number of problems. To be considered a paradigm, I think it'd have to be much more generally useful, and approach you can use for basically everything, like functional, OO or generic programming.

I think xtofl really nailed it: Generic programming is about making your code type-unaware. (A std::vector doesn't care, or need to know what type is stored in it. It just works.)

Metaprogramming on the other hand, is about type computations. Given type T0 and T1, we can define a type T2, just like how we can, given integers N0 and N1, we can define a N2 that is the sum of N0 and N1.

The Boost.Mpl library has an obvious example of this. In your normal code, if you have the integers N0, N1 and N2, you can create a std::vector containing these three values. I can then use some other algorithm to compute an index, and then extract the value stored at that location in the vector.

Given types T0, T1 and T2, we can create a mpl::vector containing these three types. I can now use some other algorithm to compute an index at compile-time, and extract the type stored at that location in the vector.

like image 198
jalf Avatar answered Nov 05 '22 15:11

jalf


You really have to differentiate between generic programming (which is kinda type-unaware) and metaprogramming, which is a perfectly legal way to do calculations within the type system.

Generic programming is very useful when you find a generalizable pattern in a lot of code. If the difference in the pattern lies not only in variable values, but also in different types, generic programming is useful to refactor the code.

Metaprogramming is applicable in a totally different domain. That domain is, indeed, quite new, and needs some exploring of your own. It is fun, too!

One very useful, and common, metaprogramming pattern is the Traits/Policy concept.

like image 12
xtofl Avatar answered Nov 05 '22 15:11

xtofl


C++ Template metaprogramming is a powerful code obfuscating technique that's applicable to a range of applications:

  • When you want to write code that nobody else on your team can understand
  • When you want code that you won't be able to understand 7 days after you wrote it
  • When code performance is more important to you than maintainability
  • When you want to be able to list "Template Metaprogramming" as a skill on your resumé.
  • When you need to write code that's unlikely to work on many real-world compilers
  • If you'd rather eat razor blades than use preprocessor macros

One other case:

  • If you want to you know how the Boost libraries work under the hood, or you want to contribute to them.

The distinction between "generic programming" (think STL containers, auto_ptrs etc), which is what C++ templates were designed to accomplish and "template metaprogramming" (use of the template system to get the compiler to effectively "run algorithms" for you) is important.

I'm all in favour of the first, but find it hard to see real-world benefits from the latter.

like image 10
Roddy Avatar answered Nov 05 '22 16:11

Roddy