Factorial macro example in C++23 metaprogramming,<p><pre><code> #include <iostream>
consteval long factorial (int n) {
if (n == 0) return 1;
return n * factorial(n - 1);
}
int main() {
std::cout << factorial(7) << std::endl;
}
</code></pre>
Exercise for the reader if using VC++ or clang/ninja, use <i>import std</i> instead.<p>-- <a href="https://godbolt.org/z/TWe11hM6j" rel="nofollow">https://godbolt.org/z/TWe11hM6j</a><p>Nicely put 5040 in ESI register at compile time.<p>Granted, C++ isn't Lisp, but already has quite a room for creativity at compile time, and C++26 might finally have compile time reflection as well.
Common misconception of non Lispers that macros are equivalent to compile time programming. You’re not simply moving the evaluation to compile time, you’re moving it upwards outside the program space into a higher dimension of programmability.<p>Not to dog on C++ unfairly, CTE is pretty neat after all.<p>Funnily enough, PGs “On Lisp” has some really neat macros in it that demonstrate capabilities that just can’t be replicated with template based macros, iirc.
<p><pre><code> (defmacro factorial (n)
(labels ((fact (m)
(if (= m 0)
1
(* m (fact (1- m))))))
`,(fact n)))
</code></pre>
The `, has no use here and can be removed. Here the backquote and the evaluation just returns the computed value.<p>Thus, this is okay:<p><pre><code> (defmacro factorial (n)
(labels ((fact (m)
(if (= m 0)
1
(* m (fact (1- m))))))
(fact n)))
</code></pre>
LABELS defines local recursive functions. The macro returns the result of calling FACT, which is a number and which is a valid <i>form</i> in Common Lisp. A number evaluates to itself.<p><pre><code> CL-USER > (macroexpand-1 '(factorial 10))
3628800
T</code></pre>
Agreed with the technical content and conclusion. However, I think it is worth pointing out that since C++11, it has had a mechanism to specify (maybe) compile-time computations that are written in plain C++: constexpr, <a href="https://en.cppreference.com/w/cpp/language/constexpr" rel="nofollow">https://en.cppreference.com/w/cpp/language/constexpr</a><p>(My parenthetical "maybe" is that I don't think compilers <i>have</i> to compute constexpr expressions at compile time. The compiler will be forced to when such expressions are used in contexts that require values at compile time. But I think it would be permissible for a compile to defer computation of a constexpr to runtime if the value isn't needed until runtime.)
Lisp macros can take arbitrary parameters and are written in lisp.<p>C++ macros can only take types and numbers (until variadic), and writing any code to operate on those inputs is challenging.
C++ templates do have the advantage that they can dispatch on their argument types. Lisp macros are expanded at a purely syntactic level, well before the compiler attempts to do any type deduction, and you cannot provide different macro expansions for different argument types without heroic efforts (which will most likely be specific to a single Lisp compiler). Dispatching on argument types is very useful in expression template based metaprogramming, for example in the Eigen library for linear algebra (<a href="https://eigen.tuxfamily.org/" rel="nofollow">https://eigen.tuxfamily.org/</a>).
Another post comparing C and lisp Macros: <a href="http://lists.warhead.org.uk/pipermail/iwe/2005-July/000130.html" rel="nofollow">http://lists.warhead.org.uk/pipermail/iwe/2005-July/000130.h...</a><p>HN discussion: <a href="https://news.ycombinator.com/item?id=31199992">https://news.ycombinator.com/item?id=31199992</a>
It’s clumsy because C++ templates are an implementation of generic and dependent types, while C++ constexpr and consteval functions are for arbitrary computation. The fact that template metaprogramming _can_ be used for arbitrary computation is actually an unhappy accident of its design that was only proven after its publication.
I don’t have any experience with Lisp. But I think C++ templates and Rust macros are both super bad and impoverished compared to what can be done in Jai.<p><a href="https://www.forrestthewoods.com/blog/using-jais-unique-and-powerful-compiler-for-typesafe-units/" rel="nofollow">https://www.forrestthewoods.com/blog/using-jais-unique-and-p...</a>