From my experience, macros make the best impression on people when they see how it helps to produce code, that cannot be made by the procedures or other constructs. Very often such things may be described as:
<common code>
<specific code>
<other common code>
where <common code>
is always the same. Here are some examples of such schema:
1. The time
macro. Code in a language without macros will look something like this:
int startTime = getCurrentTime();
<actual code>
int endTime = getCurrentTime();
int runningTime = endTime - startTime;
You cannot put all common code to procedure, since it wraps actual code around. (OK, you can make a procedure and pass actual code in lambda function, if the language supports it, but it is not always convenient).
And, as you most probably know, in Lisp you just create time
macro and pass actual code to it:
(time
<actual code>)
2. Transactions. Ask Java-programmer to write method for simple SELECT
with JDBC - it will take 14-17 lines and include code to open connection and transaction, to close them, several nested try-catch-finally
statements and only 1 or 2 lines of unique code.
In Lisp you just write with-connection
macro and reduce code to 2-3 lines.
3. Synchronization. OK, Java, C# and most of the modern languages already have statements for it, but what to do if your language doesn't have such a construct? Or if you want to introduce new kind of synchronization like STM-based transactions? Again, you should write separate class for this task and work with it manually, i.e. put common code around each statement you want to synchronize.
That was only few examples. You can mention "not-to-forget" macros like with-open
series, that clean-up environment and protect you from recourses leaks, new constructs macros like cond
instead of multiple if
s, and, of course, don't forget about lazy constructs like if
, or
and and
, that do not evaluate their arguments (in opposite to procedure application).
Some programmers may advocate, that their language has a technology to treat this or that case (ORM, AOP, etc), but ask them, would all these technologies be needed, if macros existed?
So, taking it altogether and answering original question about how to explain macros. Take any widely-used code in Java (C#, C++, etc), transform it to Lisp and then rewrite it as a macro.