DEV Community

Magne
Magne

Posted on

Meta-Programming and Macro capabilities of various languages

Meta-programming = the broad idea of “programs that manipulate or generate programs”. It can happen at runtime (reflection) or compile-time (macros).

Macros = one specific style of meta-programming, usually tied to transforming syntax at compile time (in a pre-processor or AST-transformer). It takes a piece of code as input and replaces it with another piece of code as output, often based on patterns or parameters.

  • Rule‑based transformation: A macro is specified as a pattern (e.g., a template, an AST pattern, or token pattern) plus a replacement that is generated when that pattern is matched.
  • Expansion, not function call: Macro use is not a runtime call; the macro is expanded before execution, so the final code is the result of replacing the macro invocation with its generated code.

Here are some programming languages and their meta-programming and macro capabilities.

NB! Take with a grain of salt. The result comes from working with perplexity.ai, and I have not had a chance to personally verify all of the cells. They do look generally correct to me overall, though. Corrections are welcome!

Metaprogramming + macro features

Here are the programming languages with their scores (out of 15) and links to their repos or homepages:

Scores are out of 15 = 4 (metaprogramming) + 3 (compile‑time facilities) + 8 (macro features).

Each cell is either (yes) or (no / limited).


Feature / language Racket Common Lisp Scheme (R7RS‑small) Rust Nim Carp Clojure Jai C++ Zig comptime Ruby
 
Metaprogramming features:
Runtime metaprogramming (e.g., open classes, define_method, method hooks)
Runtime reflection / introspection
Runtime eval / dynamic code loading
Build‑ or tooling‑level code generation supported
Metaprogramming score (out of 4): 4 4 3 1 1 1 4 1 2 1 4
 
Compile‑time facilities (not strictly macros): Racket Common Lisp Scheme (R7RS‑small) Rust Nim Carp Clojure Jai C++ Zig comptime Ruby
Run arbitrary code at compile time ✅ (constexpr)
Types as values at compile time ✅ (– but in Typed Racket) ✅ (constexpr + templates)
constexpr‑style type‑level / compile‑time computation ✅ (const‑eval) ✅ (via constexpr)
 
Macro features: Racket Common Lisp Scheme (R7RS‑small) Rust Nim Carp Clojure Jai C++ Zig comptime Ruby
Hygienic identifier binding ✅ (gensym but manual)
Operate on AST / syntax tree
Pattern‑based transformations
Define new syntactic forms
Define new keywords / syntax
Override core language forms
Multi‑phase / macros of macros
Full‑fledged DSL / language building (via macros)
 
Macro & compile time features score (out of 11) 11 9 9 10 9 6 6 4 3 3 0
 
Total score 15 13 12 11 10 9 10 5 5 4 4
Racket Common Lisp Scheme (R7RS‑small) Rust Nim Carp Clojure Jai C++ Zig comptime Ruby

The score counts one point per row where the language can reasonably do what the feature describes (DSL‑building is counted as a full feature, even if “limited” in some languages).

The feature score is not an ultimate measure of meta-programming power, since a language (like C++) may have a higher score than another language (like Ruby), but generally be considered less tailored for meta-programming than the other language (Ruby is generally revered for its powerful meta-programming abilities).

Macro features are varied and many, and thus in the total score they gain an undue weight, although runtime meta-programming may be just as, or even more, powerful.

Lisp-style languages (with their homoiconic S-expressions) make out 5 of the 11 languages in our list: Racket, CL, Scheme, Clojure, Carp.

Top comments (0)