Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

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).


My experience that a certain systems programming language of Unix origins featuring 1 namespace and an unhygienic token-based macro system also has few issues with function-name capture, even in code bases with seven digit LOCs.

That makes me severely disinterested and skeptical about hygienic macros.

They are too weird for the little benefit they provide. You can't look at a piece of code and know what it expands to.

Hygienic macros break lexical scope, because code produced by a macro being invoked in some file "A.lisp" is seeing lexical variables defined in some different file "B.lisp". Lexical scope must be physically enclosed and contained. If you expand it here, it sees the variables that are here, and not some other ones elsewhere that you don't see here.

Given a nesting like (x (y (z a))), if y binds a, that must be like a brick wall; there is no way that the a reference in z can get around it, to connect with a binding of a produced by x. Either that a refers to z's own binding, or else to y. Yet hygienic macros can perpetrate a lexical-scope-destroying wormhole which can do that: the inner a reference can bypass a definition set up by y, and go to the one in x.

It's a downright security issue, like going around your company's firewall, or escaping a container or chroot jail or whatever.


All I know is that in Python, JS and Clojure is I’ve accidentally written code like:

    def foo(str):
      v = str(1)
      . . .
Which resulted in head-scratching errors like “str is not a function”.

EDIT: I agree that hygienic macros aren't the right way to solve this issue.


With Lisp-2 designs as discussed in the article this is not an issue, as variables and functions are in different namespaces:

  CL-USER> (defun foo (list) (list list))
  FOO
  CL-USER> (foo 42)
  (42)
In this case the function attached to the symbol LIST is applied to the argument with the same name, but that isn't a problem.

To further illustrate, in the above example the LIST symbol is imported from the package COMMON-LISP and has a function, plist etc. attached to it:

  CL-USER> (symbol-package 'list)
  #<PACKAGE "COMMON-LISP">
  CL-USER> (symbol-function 'list)
  #<FUNCTION LIST>
  CL-USER> (symbol-plist 'list)
  NIL


Yeah, I’ve been writing Common Lisp for six years now: Lisp-2s, IMO, make the right trade-offs


Macros don't appear in your code example, so they cannot solve anything.


> My experience that a certain systems programming language of Unix origins featuring 1 namespace and an unhygienic token-based macro system also has few issues with function-name capture, even in code bases with seven digit LOCs.

The "certain systems programming language" with its unhygienic macros hides all the resulting horrible mess in reserved symbols that litter both the macro code itself and the code produced by the macros. This is perhaps tolerable so long as you're not maintaining any of those macros and you never need to look at the code after macro-substitution has occurred.


I'm confused about what you're saying about "breaking lexical scope". Lexical scope means that variable references refer to their lexically-enclosing bindings, ie references in A.lisp refer to bindings in A.lisp. That's exactly what hygenic macros do.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: