upvote
As someone who is "into" programming languages (and making toy implementations of them), I think some of the most important macros are along the lines of Rust/Haskells `derive/deriving` for quickly enabling serialization, printing etc. Using a language without such capability quickly becomes frustrating once you move to any kind of "real" task.
reply
In any kind of real task, serialization is not the hard part.

If you can write a meta program for it, you can execute that in CI and spit out generated code and be done with it. This is a viable approach in any programming language that can print strings to files.

It’s not frustrating, but maybe it feels tacky. But then you shrug and move on to the real task at hand.

reply
You say that, but I've run into real production problems which were ultimately caused by bad serialization tooling. Language semantics are never going to be your biggest problem, but rough edges add up and do ultimately contribute to larger issues.
reply
Lisp macros are more for not having to write the same type of code (all subtly different, but sharing the same general structure).

One such example is the let-alist macro in elisp

https://www.gnu.org/software/emacs/manual/html_node/elisp/As...

Dealing with nested association lists is a pain. this let you write your code with a dot notation like jq.

Macros are not only for solving a particular task (serialization, dependency injection, snippets,…) they let you write things the way it makes sense. Like having html-flavored lisps for template, sql-flavored lisp for query,… Lisp code is a tree, and most languages are trees, so you can bring easily their semantic in lisp.

reply
Yeah I strongly agree. I think the issue is that metaprogramming is complicated, so people (especially early in their careers) tend not to do it themselves, and only notice it when it's making their lives difficult. But there are a lot of cases where a little bit of judicious metaprogramming makes life MUCH easier. If you treat metaprogramming as a first-class tool, countless rough edges will smooth themselves out for you—everything from `#derive[Clone]` to `#derive[Serialize]`.
reply
Ruby, Python, and Typescript use metaprogramming rather heavily. They lack the homoiconic property of lisps, but they can do both higher-order functions and monkey-patching.

Meta-heavy code usually offers a nice DSL, but is proportionally harder to drill down through.

reply
Lisp code is a tree, which fits how most languages are written. So it’s easy to embed other languages in lisp. But other languages grammars are very cumbersome and can’t fit one another.
reply
And yet we have done it across most modern languages, with a lesser experience as Common Lisp or Scheme.
reply