In this case I'm referring to C# T4.
New developers (less than 10 years professional experience) seem to become fascinated by "cool" language features that let them do unintuitive things and then approach problem solving with a mindset of "What cool tricks can I do to solve this?"
Instead, the experienced developer will always approach a problem with "What is the simplest way to solve this problem?"
For instance: say you have an app with 30 different ViewControllers, and you need them to respond to the same notification. Sure, you could go back and refactor every one to subclass from another class that inherits from UIViewController - but then you need to make that for UITableViewControllers and UICollectionViewControllers, and potentially any other new view controllers that come along if your codebase ends up lasting for years.
Or, you could make one class category that method swizzles the viewDidAppear method to add the notification handling in immediately. Every class that inherits from UIViewController will now respond to that notification.
Oh, I read your link. So you add more behavior to it, not override it completely.
By that link's definition, then yeah, it's basically monkey patching.
Sometimes the quickest or even the most elegant solution isn't necessarily the "best" one. Best being a subjective term, I would say it depends on what you need from your code over time and with whom.
The alternative is to just write the same conservative solution for ten years. Then you are just as medioker programmer after ten years as when you started.
The classic analogy is with young musicians. Just because you can put a fancy ornament in or play real fast doesn't necessarily mean you should. Sometimes it's best to play something simple, so long as it's just the right something simple.
And what would you call my mindset, which can be summarized as "what cool features I can use to express the problem and it's solution in a simplest way"?
Remember, copy pasting is also very simple solution to many common problems.
Said library can then document (and test) the interface and implementation sufficiently to add a minimal amount of complexity to the application code.
The big red flag is using this stuff in application code to hack around bad design decisions or save on a small amount of typing (there's also no barrier to its expanding and engulfing the entire codebase).
One of the less well known rules of thumb from extreme programming was to have just 5 to 7 "things you have to know" to write good code for a system. Only up to two of those things should be notably abstruse or automagically implicit. Preferably, it should be zero, and any fancy tricks should be transparent for most coding.
Really, this just follows from optimizing code for reading.
Anyway. The need for metaprogramming is like a lesser version of the need object-oriented programming. You never strictly need OOP. And you can totally go overboard with the Abstract Factory Factory, and make your code insanely obnoxious to follow.
But it can help, and it can specifically help in the situations when it simplifies more than it complicates -- in the situations where it's so simple you barely notice it. (Describing object attributes for your favorite ORM is a case that comes to mind.) If you're set in your ways and you've already made up your mind to eschew it always, then sooner or later you're going to end up with something more complicated than it should be instead of simpler, and it's just an empty piety. :P
When I read soup10's comment, or some of the other comments here expressing a similar take on the matter, I don't see "hatred" involved.
In fact, I see a clear lack of emotion. In place of emotion is a pragmatic and analytical point of view, where the benefits are weighed against the drawbacks, and a conclusion is drawn.
Emotion doesn't really play a role at all in such analysis. It strikes me as odd to see it suggested that emotion is involved, when it pretty obviously isn't.
Functions are data, just like other kinds of data. I use them in C whenever what I want to parameterize is behavior, and not, say, an integer or a string.
I believe that if you explicitly avoid function pointers, and instead use a less appropriate construct, that would become a mess, instead. If you replace the function pointer with an enum, you've tightly coupled the type definition of the parameter with all users. You've added a switch statement on the enum, rather than a function pointer call. It would be both messier and probably slower than the function pointer.