pg's article on the topic, "What Made Lisp Different", [0] has aged poorly, and points 8 and 9 it makes (a notation for code using trees of symbols and the whole language always available) are no longer Lisp-specific. The final point, about "inventing a new dialect of Lisp", doesn't hold true either - as seen here, Julia is doing just fine not claiming to be another dialect of Lisp, even though many sources mention directly that it's Lisp-inspired.
Congrats to Julia people for the macro system and to the author for the article!
There is also a secret option to get into a lisp repl in Julia "julia --lisp".
Wtf....... what? I just tried it, it's true. Is this some easter egg?
After that, I realized that macros aren't always something that needs to be avoided; in the right hands they're immensely powerful.
I've only played a little with Julia macros, but it seems like they learned a lot of Lisps lessons, so I support it wholly.
[1] I wasn't aware of how Objective C was built at the time.
Maybe it is better now but when I looked at macros ~5 years ago some language update changed the ast produced by the parser and I basically gave up.
I like that Julia offers some macro-like techniques that replace a lot of the cases where one might use a macro for performance reasons.
For example, maybe you want to handle something that looks like:
foo ~~> bar
In lisp syntax (and recall that is what the Julia ast is: everything is a head and then arguments) it might look like: (~~> foo bar)
; or
(op ~~> foo bar)
But if you change to e.g. foo ~~> bar + 5
You might get (+ (~~> foo bar) 5)
Or (~~> foo (progn (+ bar 5)))
I don’t remember what you got or which cases were tricky, only that I could never guess what the output of dump would be.Was the language even stable then?
Consider how ergonomic testing is thanks to macros: https://docs.julialang.org/en/v1/stdlib/Test/
Here's an example of passing quasi-json to a plotting function: https://www.queryverse.org/VegaLite.jl/stable/userguide/vlpl... . This lets you essentially transliterate a VegaLite spec into Julia without needing to translate it into Julia.
Finally, macros that operator on dataframes let you write code that looks kind of like SQL, and is much more pleasant than working with functions: https://dataframes.juliadata.org/stable/man/querying_framewo...
However, it is useful to provide a nicer syntax and DSLs.
Some examples: https://stackoverflow.com/questions/58137512/why-use-macros-... https://www.juliafordatascience.com/animations-with-plots-jl... https://gist.github.com/MikeInnes/8299575
(define-all i 5 0)
;; creates i1 i2 i3 i4 i5 initialized to 0
That's somewhat impossible with functions. The closest you get is either an array/dict with only runtime error checking, or an external codegen program.I wrote a post [0] about how to do this in Racket. The macro generates ORM code based given a SQLite DB. Aka the compiler queries SQLite and generates table-column functions automatically.
More potential benefits are: Better static error messages (can implement a type system using macros, example here[1]), and controlling execution order (can add lazy computation semantics).
[0]: http://tech.perpetua.io/2022/01/generating-sqlite-bindings-w...
[1]: https://gist.github.com/srcreigh/f341b2adaa0fe37c241fdf15f37...
While NSE enables the dplyr syntax that many people enjoy, for me it's too magic and I have trouble reasoning about variable names in other people's code.