A programmer who has never heard of exceptions may say: "What, so exceptions can interrupt the normal program flow at any time!?" or "Why would I ever want to handle error conditions at a different part of the program? I handle errors right after every function call." or "Exceptions sound scary and inconsistent".
A programmer who has never heard of garbage collection may say: "What, I can't tell ahead of time how much memory my program is going to use?", "I want to know when my program allocates memory and frees it. This shouldn't happen nondeterministically!" or "Automatic memory management sounds scary and unpredictable."
(defconstant +logging-enabled+ t)
(defmacro log-message (message)
(when +logging-enabled+
`(err-say ,message)))
(log-message (crazily-expensive-computation))
Like other structures, they can be abused or used with great success. Based on my limited experience with a number of quicklisp-downloaded packages, I have found macros helpful and unnoticeable as macros.Irony: Fewer bracing symbols.
In the next blog post, I am hoping to see how perl 6's macro feature handles the parsing of passed-in code. Specifically, I would like to see an example for do-in-reverse:
(defmacro do-in-reverse (&body commands)
`(progn ,@(reverse commands)))
(do-in-reverse
(princ "First")
(princ "Second")
(princ "Third")))
Prints "ThirdSecondFirst"So I can only guess what it would look like; take the following with a rock of salt:
macro do-in-reverse($code) {
$code.clone(statements => $code.statements.reverse);
}
do-in-reverse {
say 'First';
say 'Second';
say 'Third';
};
But it might turn out not be that simple.The diffulcty comes from the fact that unlike Lisp, in Perl 6 not everything is a list, so you can't treat the AST as a list (... of lists, possibly) either. The .clone would take care to preserve things like outer lexicals and the signature of the block (you don't see it; it's implicit) and other non-listy things.
doInReverse := method (
m := call argAt(0)
stmts := list() // list of statements (ie. messages)
loop (
rest := m next // rest of messages after current
stmts append(m setNext) // get current message
m := rest
if (m == nil, break) // exhausted statements when "nil"
)
stmts reverseForeach (n, doMessage(n))
)
doInReverse(
writeln("First")
writeln("Second")
writeln("Third")
)
Of course this is easy in Io because everything is just a message.NB. The above code doesn't actually amend the AST but it could. Here are some previous examples of amending AST in Io posted here: http://news.ycombinator.com/item?id=1810480 http://news.ycombinator.com/item?id=1804599
macro do_in_reverse($value, @code) ...