No. How would that be the case?
> And making maintenance more difficult
If used poorly, sure; the same is true of most features of most languages.
> (aren't you re-inventing a new language with macros?)
You are extending the existing language with them, much as you are when using a language with user-definable functions rather than only builtins.
No. How would macros break homoiconicity? They expand into atoms and lists (and other datatypes), the same stuff of which macro-free programs are made.
>And making maintenance more difficult?
No. Unless you intentionally write unmaintainable macros. It's the same as if you write unmaintainable functions, classes, etc. They're just abstracting a different thing— syntax.
>aren't you re-inventing a new language with macros?
No, you're expanding the language; you're just expanding the grammar instead of the vocabulary.
>Where does the "First rule of the macro club" coming from? When should you break it?
What is the "first rule of the macro club?"
You should break that rule only when the behavior can’t be written as a function, such as these cases:
• The call needs to avoid evaluating its arguments. For example, the `if` built into the language is sometimes defined as a macro.
(if (= (+ 2 2) 4)
(print "math works")
(print "math is broken"))
If `if` were a function, it would first print both statements, and then return the return value of `print` in whichever branch. By making `if` a macro, it can avoid evaluating the branch that is inapplicable.• The call relies on information about the environment only available at compile-time. Perhaps the macro reads a configuration file on the developer’s computer to decide how to set something up.
• You have profiled the program and determined that it is better to run the function at compile-time. For example, you might want to make `(regex "[a-z][a-z0-9]+")` compile the string to a regular expression at compile-time instead of run-time.
I think it would be more appropriate to use a compiler macro here.
If used right, macros make things much more maintainable. If you have a hundred nearly-identical codeblocks, where only (say) a string constant is varying, and suddenly you need to change what those blocks do, bam, you've got a hundred blocks to change. If those blocks had been refactored with a macro, all you have to do is change the macro once. It also prevents the new guy from coming and doing a bandaid fix to line #72 making it slightly different from the 99 lines around it and making your life a living hell.
if ( key == "hitpoints" ) {player.hitpoints = value; return;}
if ( key == "mana" ) {player.mana = value; return;}
Those "return"s make it rather awkward to use a function. At best, said function would have to return a bool and you'd end up with something like
if ( maybe_assign( key, "hitpoints", &player.mana ) ) return;
which hardly gains you anything and in fact reduces readability a fair amount.
I listed some situations where you need a macro in my comment that explains the “first rule of the macro club” you asked about: https://news.ycombinator.com/edit?id=9513988
And making maintenance more difficult (aren't you re-inventing a new language with macros?)?
Where does the "First rule of the macro club" coming from? When should you break it?