Macros make Elvis better
Standard disclaimer: Clojure is a new hobby.
The C programming language provides a ternary operator. It's a terse if/else expression:
const char *text = (str != NULL) ? str : "null";
printf("%s\n", text);
}
The team behind the Groovy programming language took a look at the ternary operator and realized something. Developers frequently use it during a variable assignment to take the value of the test expression when not null, otherwise take the value of the "else" expression. A new operator was added to the language to support exactly this usage and was dubbed the Elvis operator.
The Scala programming language does not have an Elvis operator, but Daniel Spiewak posted an impressive implementation.
This led me to thinking about defining the Elvis operator in Clojure, my current spare-time language. Clojure is a Lisp hosted on the JVM (with some plans for the CLR). This was a fun exercise but I make no claims that this is a good way to be Elvis-ish in Clojure.
First, here's a naïve implementation:
(if-not (nil? a) a b))
It works:
123
user> (elvis_fn nil 456)
456
But it always evaluates the "else" expression. FALE.
(println (format "Sleeping for %d ms" duration))
(Thread/sleep duration)
duration)
user> (elvis_fn (nap 123) (nap 456))
Sleeping for 123 ms
Sleeping for 456 ms
123
So that's bad. Let's make a macro version. This should prevent the expressions from being evaluated before Elvis gets a chance to do his thing:
(if-not (nil? a) a b))
user> (elvis_macro (nap 123) (nap 456))
Sleeping for 123 ms
123
To verify this, I added
before the (if-not) form and called the method and the macro again:
Sleeping for 123 ms
Sleeping for 456 ms
Blue suede shoes
123
user> (elvis_macro (nap 123) (nap 456))
Blue suede shoes
Sleeping for 123 ms
123
So it was easy to avoid evaluating things by simply making the function into a macro. I'm sure there are many things above and beyond what I am doing here, but it was a nice experiment.


