Live data from Hacker News

The Problem with Macros

ianthehenry.com

21–30 of 70 posts

Re: The Problem with Macros

#21
May be unrelated, but that's why I prefer the way JS approach this kind of problem: JS doesn't have macros.

People use callback function to achieve almost the same thing

  function doTexture(texture, fn) {
    beginTextureMode(texture)
    fn()
    endTextureMode()
  }
  
  doTexture(myTexture, () => {
    drawCircle()
    drawRectagle()
  })
At the cost of being more verbose, we get the benefit of one thing less to learn; and simplicity is a powerful feature IMO.

I guess why this is less popular in lispy languages is because

  1. macro
  2. callback functions introduce more indent levels :(

Re: The Problem with Macros

#22

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 d…

> I purport solving this problem is akin to solving a 0.00000001% issue

It seems like Common Lisp has done quite a lot to solve this problem already, which is why it is a non-issue in Common Lisp.

> non-externalizable, non-PRINTable function objects

Yes, this would be a very annoying technique in a language with non-externalizable, non-PRINTable functions.

> This is contrary to Lisp’s DNA of interactive development and is a big no-no.

Redefining functions interactively is actually a great motivating case for cross-stage persistence. Instead of interpolating the value of the function, interpolate the lexical binding of the function itself, and then redefinitions will be reflected automatically in any expansion of the macro.

Re: The Problem with Macros

#23

> I had already, at this point, verified that this is something you can do in Common Lisp. [...] But maybe… maybe you couldn’t do this back then? On Lisp was published in 1993. Maybe… maybe Common Lisp macros were entirely syntactic in 1993? Is there a chance that this is some, like, recent development in the lisp world? Paul Graham mentioned this (EDIT: something like this, but probably with a different answer) once…

I think there might be another issue here: function objects aren't "externalizable" and so you can run into weird errors if you try to compile a form with literal functions.

Re: The Problem with Macros

#24

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 d…

I strongly agree here: my experience is that a Lisp-2 with namespaced symbols has very few issues with function-name capture. While, at one point, Lisp-2s may have been for performance or other implementation details, I find that Lisp-2s are much nicer to code in because you just don't worry about name collisions (as long as you know a handful of relatively simple rules about macros).

Re: The Problem with Macros

#25

> I had already, at this point, verified that this is something you can do in Common Lisp. [...] But maybe… maybe you couldn’t do this back then? On Lisp was published in 1993. Maybe… maybe Common Lisp macros were entirely syntactic in 1993? Is there a chance that this is some, like, recent development in the lisp world? Paul Graham mentioned this (EDIT: something like this, but probably with a different answer) once…

Odd, no implementation I tried (abcl, ccl, clisp, cmucl, sbcl) today permits such a form.

Hmm. Yeah, you're right. (Come to think of it, when I originally read it, I think I interpreted "what you'd expect" to be "raising an error", or at least I deduced that after trying it myself in SBCL.) Edited my comment.

Re: The Problem with Macros

#26

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 d…

> redefining that function won’t take effect in previously expanded code Yeah, that is an important issue. What do you think of the following solution? 1. The semantics of the language are that, every time a function is called, any macros in its body get reexpanded. 2. The language implementation is expected to notice that, in normal cases, neither the macro nor the functions it calls have been redefined, and therefo…

The data needed for (2) is mostly already available: most lisps maintain a Xref database and Slime already has a binding for `slime-who-macroexpands`[1]. Integrating this performantly into the compiler might be interesting, but I think it's theoretically tractable.

[1]: https://common-lisp.net/project/slime/doc/html/Cross_002dref...

Re: The Problem with Macros

#27
post #21

May be unrelated, but that's why I prefer the way JS approach this kind of problem: JS doesn't have macros. People use callback function to achieve almost the same thing function doTexture(texture, fn) { beginTextureMode(texture) fn() endTextureMode() } doTexture(myTexture, () => { drawCircle() drawRectagle() }) At the cost of being more verbose, we get the benefit of one thing less to learn; and simplicity is a powe…

I debated mentioning this explicitly, but decided it was just noise next to the rest of the post. But you should note that, while that macro can be easily replaced with lambdas without much change in ergonomics, there are lots of much more interesting things you can do with macros that do not have equivalent substitutes in a language like JavaScript. (e.g. JSX exists as its own weird pre-processor thing, but you could theoretically just do it with macros instead, and then it could compose with other syntax extensions.)

> we get the benefit of one thing less to learn

But learning programming language theory is the best part :)

Re: The Problem with Macros

#28

> I had already, at this point, verified that this is something you can do in Common Lisp. [...] But maybe… maybe you couldn’t do this back then? On Lisp was published in 1993. Maybe… maybe Common Lisp macros were entirely syntactic in 1993? Is there a chance that this is some, like, recent development in the lisp world? Paul Graham mentioned this (EDIT: something like this, but probably with a different answer) once…

I think there might be another issue here: function objects aren't "externalizable" and so you can run into weird errors if you try to compile a form with literal functions.

Why aren't they externalizable? You could print a lambda as #. The arglist and probably the body would be straightforward (unless the body contains more literal functions, but then you recurse). Printing the env might involve printing complex or even circularly linked structures, but it's no more difficult than pretty-printing objects in general. (Some things, like a pointer to an FFI object corresponding to an open GUI window, would be difficult to serialize, but there are many use cases that don't involve putting those things into the body or env.)

Printing primitive functions could be something like #, and when an implementation read in a thing like that, it would look in its own set of primitive functions for one named '+ and use that; with a reader macro I imagine you could make that exact syntax work. (In fact, you could print # on an x86 machine and read it on an ARM machine, and this could be fine.)

I honestly don't see why implementations haven't done this, other than "it was more bothersome than worthwhile".

Re: The Problem with Macros

#29
People have macro use cases more often than they think. I work in devops these days and almost every week I have a situation where I have to generate repeated patterns of code using the language in which Im writing code(Python/Shell/Perl etc).

Many times these are done through what is known as manual work. In my experience if someone is complaining about laborious manual work. Lack of quick automation, they are basically in a scenario where the language lacks features to generate code to do work, which they have to now do instead.

Its for this reason I have to write adhoc perl scripts to generate shell commands, and sometimes even whole shell/python snippets/mini-programs. All because Perl makes it easy to generate text(code). Perl now acts as a macro facility for Shell/Python.

If you pay close attention these patterns will begin to show all up over the place.

Re: The Problem with Macros

#30

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

Thank you for this. My brain is complete mush after days of reading papers about the history of lisp, but this is at the top of my reading stack once I can get my eyes to focus again.
Post reply on HN