2 ms·
The frustration of Julia macros for me was never knowing what AST would be produced for a given expression. This is a bit more manageable if you have a typed AS
by dan-robertson 5y ago
The frustration of Julia macros for me was never knowing what AST would be produced for a given expression. This is a bit more manageable if you have a typed AST (e.g. OCaml but ppxes have other issues) or an obvious one (e.g. lisp). I like the way rust handles it where the macros operate on a tree of non-delimiter leaves and [delimiter, subtree list, delimiter] nodes which can allow for figuring out what the input to a macro will be more easily and for more varied macro syntax. Other languages that want a full AST before macros force the macro input to be a bit more AST-like, e.g. the Julia parser picks operator precedence and OCaml won’t let you use _ as an identifier.
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.
- dunefox 5y ago> ~5 years ago Was the language even stable then?
- adgjlsfhk1 5y ago5 years ago was right before 1.0, so a ton of stuff was broken since it was the last chance.
- StefanKarpinski 5y agoTip: the first move when trying to write a macro is doing `Meta.@dump` on examples of argument expressions you want your macro to consume and produce. Then write code that transforms the inputs to the outputs.
- dan-robertson 5y agoRight but it wasn’t obvious to me (at the time) what a change to the source code would do to the ast, so it wasn’t easy to know all the cases to handle, especially with quasiquotation (I think double-backtick style programming was basically impossible). 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.