You don't need metaprogramming to have this problem.
True, in fact it was an example of a more general idea.
There was also the complaint from some developers that C is
"superior" to C++ because in C++, a method call in a complex
class
hierarchy can theoretically end up "anywhere", whereas in C,
you at
least know exactly which function will get called, since there
is no
overloading.
That's an extreme opinion, tools are tools, it's not that we
always have to operate in the strictest ways possible, but yes
I'd say you have to be conscious of the consequences.
Nowadays my rule of thumb is to ask myself -do I need this- when
thinking of grabbing a given language feature for a given
implementation. Do I need a class? What would it give me? If it
ends up with considerable savings then go ahead.
Now you discover a bug somewhere in this function. How would
you go
about finding where it is? Well, since this is C, which
allegedly
doesn't have any polymorphism, that should be trivial, right?
Just trace
through all of the function calls and narrow it down. Except...
all of
those ops.xxx() calls are function pointers. So OK, we need to
find out
where they point to.
Yeah... That decision was quite bad (especially today!), as you
point out they didn't avoid polymorphism really, just
re-implemented it in a language that doesn't support it natively
in its type system, and that is often trouble.
That's why I actually am wary of certain forms of
metaprogramming, I don't think it's often a good idea to try to
extend a language beyond what its syntax natively supports, not
only because it surprises people, but also because it will
surprise tools and so on...
[...] you only
need to remember add and delete, and the abstraction takes care
of
itself by resolving to the correct overload based on the
argument types.
That is not really OO though or well not what I mean with OO/OOD.
The OO that I would avoid is the "thinking in objects" mindset.
Associating functions with types is the simplest form of
polymorphism and it's totally fine, you don't even need classes
for that! But even if you face a problem where you do actually
need interfaces over objects, go ahead, I'm not saying it's never
useful. But it shouldn't be the "default" state of mind and
certainly how to split computation in objects shouldn't be the
way we think about solving problems, that's the bad of OO
mentality that degenerated into horrors like "patterns".
Computation is algorithms that change bits of data.
Metaprogramming goes one step further and lets you reduce
boilerplate --
True, I just wanted to show the tradeoff that are entailed in
that. Then it can still be useful, but a lot of times is just
abused, and many, many times we would be better served by a
better type system than having to hack features via
metaprogramming.
I would be much more open to generics if we had in C++ bounded
parametric types (concepts... or C# style generics) rather than
templates. And I would use C++11 lambdas, even if I wouldn't have
touched with a mile-long pole the Boost::lambda stuff, and so
on...
At the end of the day, *all* tools must be used with care. Even
in C, a
language with neither OO nor metaprogramming support, you can
code
yourself into a nasty mess by using built-in language
constructs like
function pointers, like I showed above. Just because you *can*
cause
serious injury to yourself with a hammer, doesn't mean that
hammers
are inherently evil.
Right, but we live in a world where it seems to me lots of people
are hammer happy :)