Live data from Hacker News

The Problem with Macros

ianthehenry.com

1–10 of 70 posts

Re: The Problem with Macros

#2
As a relative Lisp novice, I think this article is excellent! I really enjoyed it, both from a technical and also an entertainment perspective. Time to put the rest of the blog post series on my ever-growing reading list….

One minor typo (I thought it was pretty funny): “it seems like it was actually a performance hack in order to make a dynamically typed language performant on the hardware of the early 1890s.” Or, did Babbage’s machine run Lisp the whole time?

Re: The Problem with Macros

#3
This is quite a wild ride. My only Lisp experience is Clojure, and I have written some macros[1], but never dove anywhere near this deep into everything that’s going on.

It’s interesting, I’ve spent a lot of recent personal interest time deep diving into code transformation in JS/TS. These concerns about name collision and shadowing are front and center there, but of course tree-walking AST transform is the ~only game in town[2] and it’s had me pining for first class language macros.

1: The first that comes to mind https://github.com/reup-distribution/espalier

2: I have some ideas on this, but nowhere near fully formed enough to elaborate just now; suffice to say they derive a lot from what I do know about macros.

Re: The Problem with Macros

#4

As a relative Lisp novice, I think this article is excellent! I really enjoyed it, both from a technical and also an entertainment perspective. Time to put the rest of the blog post series on my ever-growing reading list…. One minor typo (I thought it was pretty funny): “it seems like it was actually a performance hack in order to make a dynamically typed language performant on the hardware of the early 1890s.” Or, d…

I assumed this was a deliberate joke.

Re: The Problem with Macros

#5

As a relative Lisp novice, I think this article is excellent! I really enjoyed it, both from a technical and also an entertainment perspective. Time to put the rest of the blog post series on my ever-growing reading list…. One minor typo (I thought it was pretty funny): “it seems like it was actually a performance hack in order to make a dynamically typed language performant on the hardware of the early 1890s.” Or, d…

I assumed this was a deliberate joke.

It seems like a pretty excellent way to refer to the 1980s.

Re: The Problem with Macros

#7
Bravo, my friend, bravo.

The unit testing macros for my Racket project were created so I could create snapshot tests for an API. The custom test-suite and test-case macros set parameters (think React context properties) for the suite and case names. There is a custom `check-snapshot` function which save snapshot files under ./snapshots/suites/{suite-name}/cases/{case-name}. It evaluates each expression and pretty-prints the results separated by newlines. It can use an env var flag to fail any test if results differ from the file, but I usually just always update snapshots and check in Git to see if/how they have changed.

One day I'll improve `check-snapshot` to copy the unevaluated expressions into the snapshot file too so they're very easy to review. This will require it to become a macro. The evaluated expressions are generally 1-5 pretty-printed lines long and stateful sequences of expressions, so it's different from React snapshots which can be pages long to display one value.

Anyways, I'm unsure if Racket macros suffer from the problem described in the post. If I'm not mistaken, this problem is kinda like a problem with unhygienic macros only? The idea of hygienic macros is that identifiers are never captured from the environment where they're used.

In Racket there's also phase separation. The tests.rkt file in my project actually has two test-suite identifiers. One at phase 0 referring to the custom test-suite macro, and one at phase 1 referring to rackunit's test-suite. Good thing the macro isn't recursive, I guess...

Re: The Problem with Macros

#9
Syntactic closures are another hygine system that provides the same construction techniques as common lisp macros, while also allowing the macro author to choose which bindings should be set in the macro's lexical environment instead of the expansion's lexical environment (or vice versa).

http://community.schemewiki.org/?syntactic-closures

Re: The Problem with Macros

#10
As unsatisfying as it may sound, Common Lisp taught me that, truly, none of this function binding capture stuff really matters in practice. Millions of lines of Common Lisp code have been running for decades without running into problems with capture. So I purport solving this problem is akin to solving a 0.00000001% issue if we measure the frequency of encountering this error writing thousands of lines of Lisp per day for a sizable chunk of one’s lifetime. The explanations by Pitman et al. are wise. If someone on my team were regularly writing macros that expanded into non-externalizable, non-PRINTable function objects, I’d probably be irritated. You’re hindering my pretty-printer, you’re hosing my debugging tools, and you’re breaking my expectations of interactive development. What? One big negative the article doesn’t cover is that if you’re essentially embedding function pointers in your macros, redefining that function won’t take effect in previously expanded code.

    (defun f () 1)
    (defmacro m () `(f))
    (defmacro n () `(,#'f))
    (defun g () (m))
    (defun h () (n))

    ; later
    (defun f () 2)
H will always return 1 (bad!). G will reflect the global binding (good!). You would have to re-evaluate the source definition of H to get it to reflect the new pointer. This is contrary to Lisp’s DNA of interactive development and is a big no-no. (You have similar issues if you, a library author, are declaring the functions you provide to application programmers as globally INLINE. It’s not for you, the library author, to choose when things should be inlined!) You can force late binding using FUNCALL on a symbol to look up the global binding

    (defmacro n++ () `(funcall 'f))
if you so please, but it’s not very satisfying. F can never be captured by the local environment there.
Post reply on HN