There has been a worthwhile discussion while I was on vacation. I want to point out a few non-obvious things about my February 9 suggestion:
Where I said "Uses of symbols other than as variable names are modified to treat internal symbols the same as external", this only happens in the parser and in complex macros that take arguments that are not really expressions. All "run time" uses of symbols are not affected; they will never see internal symbols. Any internal symbol in quoted data will become an external symbol when parsed. Also I should have said "*local* variable names" since global variable names are always external symbols. In my suggested hygienic macro system, there is no need for any AST analysis during macro expansion, nor in the *quote* special form. Such analysis would be problematic if the expansion of a macro includes macro invocations. In my proposal, rather than guessing which symbols were meant to be "hidden" by analyzing the AST, the macro writer indicates explicitly which symbols are hidden by how the quote construct is written. The default is "hidden" for symbols that appear literally in the quote since that is by far the most common case. The semantics of :symbol would not change from the *status quo* under my proposal. Perhaps :(x) should be the same as :x rather than the same as quote x end. Thus if the result of the unary : operator is just a symbol, it is always an external symbol, but the *quote* special form is able to produce just an internal symbol. On Wednesday, February 19, 2014 2:43:04 PM UTC-5, Toivo Henningsson wrote: > > To me, the natural context of a quote would just be the literal context > where it is found. > I asked "Where does the *quote* construct get the context when it makes an internal symbol?" I suggested explicit management of contexts, but I now think it would fit better into Julia if the *quote* special form implicitly accessed a symbol context created each time a function is entered or a top-level form is evaluated, analogous to the way the *return* special form implicitly accesses a control context created each time a function is entered. Thus users who want to break parts of the expander function into separate functions must pass around explicitly any local variable names that are private to the macro, since internal symbols created by separate functions will be distinct, but users never have to pass contexts around explicitly. This seems like the best way to keep the usual case simple and terse while leaving the more complex, rarer case natural although not terse. The step I have not taken yet is to read the Julia source code and try to predict how hard it would be to add this hygienic macro feature. I have not used Clojure, but I think a problem with its macro system is that any macro that wants to introduce a local variable binding in its macro expansion must explicitly use gensym. That doesn't seem to me like keeping simple things simple.
