C++ Template Macroprogramming versus Lisp Macros

(simondobson.org)

49 points | by oumua_don17 4 hours ago

9 comments

  • pjmlp 2 hours ago
    Factorial macro example in C++23 metaprogramming,

      #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;
      }
    
    Exercise for the reader if using VC++ or clang/ninja, use import std instead.

    -- https://godbolt.org/z/TWe11hM6j

    Nicely put 5040 in ESI register at compile time.

    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.

    • lispm 2 hours ago
      macro programming in Lisp would be "programming programs".

      I don't see it here. This looks like compile-time execution to compute values. If it would be a macro, it could return source code.

      • pjmlp 1 hour ago
        In general, a macro produces code at compile time, doesn't matter in which form it ends up in the binary, as long as the observable side effects are the same.

        Example of a library that generates serialization code, https://github.com/getml/reflect-cpp

        As mentioned the ongoing C++26 proposal with produce the desired source code at compile time, thus reducing the amount of code of libraries such that one.

  • lispm 1 hour ago

        (defmacro factorial (n)
          (labels ((fact (m)
                     (if (= m 0)
                         1
                         (* m (fact (1- m))))))
            `,(fact n)))
    
    The `, has no use here and can be removed. Here the backquote and the evaluation just returns the computed value.

    Thus, this is okay:

        (defmacro factorial (n)
          (labels ((fact (m)
                     (if (= m 0)
                         1
                         (* m (fact (1- m))))))
            (fact n)))
    
    LABELS defines local recursive functions. The macro returns the result of calling FACT, which is a number and which is a valid form in Common Lisp. A number evaluates to itself.

        CL-USER > (macroexpand-1 '(factorial 10))
        3628800
        T
  • thunkingdeep 1 hour ago
    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.

    Not to dog on C++ unfairly, CTE is pretty neat after all.

    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.

    • nightowl_games 12 minutes ago
      "outside the program space into a higher dimension of programmability"

      I can visualize this metaphor just fine, but I can't tell why it's useful. Can you make this concept more concrete?

  • scott_s 3 hours ago
    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, https://en.cppreference.com/w/cpp/language/constexpr

    (My parenthetical "maybe" is that I don't think compilers have 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.)

  • mgaunard 31 minutes ago
    Does this article have a (2002) that I missed or something?
  • liontwist 3 hours ago
    Lisp macros can take arbitrary parameters and are written in lisp.

    C++ macros can only take types and numbers (until variadic), and writing any code to operate on those inputs is challenging.

    • knome 3 hours ago
      • Etheryte 2 hours ago
        As a code golfer, this is beyond satisfying. Doing things in a few bytes is nice, yes, but doing them in a way no reasonable mortal ever would is even better.
      • liontwist 42 minutes ago
        There is the lisp meme “mom can we have defmacro? No we have defmacro at home”
    • spacechild1 3 hours ago
      The post is actually about template metaprogramming. 'template macroprogramming' isn't really a thing.
  • James_K 1 hour ago
    Macaroni art versus the Mona Lisa.
  • forrestthewoods 2 hours ago
    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.

    https://www.forrestthewoods.com/blog/using-jais-unique-and-p...

    • pjmlp 1 hour ago
      Except Jai is never going to get the use any of them have, so we use what is there.
    • SkiFire13 2 hours ago
      The `#modify` thing looks pretty cool, but I can't help but think how a compiler/ide is supposed to analyze the body of such function and provide suggestions. Rust macros have a similar issue, but it's offsetted by the fact that generics are pretty powerful too and can be fully analyzed by the compiler.
  • qertuiopas 1 hour ago
    Dudertiosa