I came across a blog entry that implemented a “feature” of C# called “??” in smalltalk. I like smalltalk a lot (Squeak, specifically. I’m sad that I can’t seem to find their “cipher” program anymore.). I, however, have been living in LISP land and this effort seemed to fit. So I decided to do it as a quick brain exercise 🙂
According to the aforementioned blog, the ?? operator “returns the expression to the left of the operator if it is non-nil, or that to the right if it is.” Simple enough, almost like doing “a ? a : b” in C (with “a” being cached instead of evaluated twice, I would hope!).
Given the risk of the left argument not being referentially transparent (or cheap to execute), we would need to introduce short-circuiting. The ‘if’ special form does that in lisp, so it’s just a matter of substituting that. We can’t defun the new operator, as it would evaluate both sides before passing it to the logic, so a macro looks like the right mechanism. Since LISP macros are not hygienic, we should store the cached evaluation of the left side form in a variable created by
gensym… Here’s what I came up with 🙂
(defmacro ?? (preferred alternative) (let ((ret (gensym))) `(let ((,ret ,preferred)) (if ,ret ,ret ,alternative))))
Instead of writing “preferred ?? alternative”, it’s now “(?? preferred alternative)”. A few quick tests feeding it functions that produce side effects (namely printing to the screen) demonstrate that this approach is sufficiently lazy in evaluation to avoid side-effects.
A fun little brain exercise. Yes, perhaps the equivalent of a single curl of a 2 pound weight, but *shrug* it’s all good.