Hi Per,
First question I have is :
Can you elaborate on why you decided to model black hole on syntax-rules vs other approaches like R6RS syntax-case for instance. My knowledge of those approaches is very light but it seems that if R6RS decided to scrap syntax-rules and go for another approach there must be good reasons. Can you comment on that? It would help a lot in getting an idea of the strengths and weaknesses of black hole.
Also, I read that syntax-rules doesn't support any kind of non-hygienic macros. Is that the case for black hole or did you extend it to support non-hygienic macros?
-- First, my thought about syntax-rules vs. syntax-case
It's true that syntax-rules doesn't support any kind of non-hygienic macros. All variables that the macro uses must be passed explicitly as parameters to the macro. I have not made any extension to this kind of macro. BH does not even support SRFI-46, but that should be really simple to implement when needed.
The reason I wanted to support syntax-rules are mostly pragmatic; I wanted to be able to use other people's R5RS code. Also, I wanted to make it easy for people who are writing code in Black Hole to write it in a reasonably portable way.
Syntax-rules macros are based on pattern matching, and are turing complete. However, many useful operations that are possible to do in Scheme are impossible to do in syntax-rules macros; string operations for instance.
In essence, syntax-rules is a tool for writing macros that is easy to learn and it's easy to write correct macros in it. Most macros are very simple, and syntax-rules excels in those cases. My impression is that syntax-rules was put in R5RS without very much thought, but it was still in many ways an improvement over R4RS macros (non-hygienic, I think). R5RS' specification of syntax-rules is rather hairy at corner cases, and implementations claiming full R5RS compliance often have slightly different behavior.
But, syntax-rules macros are 1) not able to break hygiene in any way 2) not able to execute arbitrary Scheme code. Syntax-case is, as I understand it, but honestly, I don't know very much about syntax-case, able to do both of these things. It seems people who don't like R6RS often criticize syntax-case for breaking the principle of lexical scope, and for being overly complex.
-- How this relates to Black Hole
Black Hole's macro system is not modelled on syntax-rules, it is based on syntactic closures, and syntax-rules is implemented in terms of syntactic closures. Implementing syntax-rules took only about a day, and it should be possible to implement syntax-case as well. I just haven't done it.
Chicken's macro system is based on explicit renaming, which might actually be a better choice than syntactic closures, because I have heard that ER is faster than SC, not sure though. So far, I haven't had any performance problems, but I am going to have to change a rather large part of the hygiene core to be able to implement let- syntax properly, and that might make it slower. (At the moment, it's not always possible to use define-syntax directly inside let-syntax)
The reason I chose syntactic closures over explicit renaming is that I think it's easier to write SC macros than explicit renaming macros. Also, I would guess that it's easier to implement syntax-rules in SC than in ER. SC is basically a little bit higher level than ER.
There is one more thing that I ought to mention. Because syntax-rules doesn't allow execution of arbitrary code, syntax-rules is very convenient for the module system/compiler/interpreter writer. Allowing execution of arbitrary code introduces all kinds of strange problems, and the only really good solution to those problems that I know of is called the syntactic tower. The syntactic tower requires all modules to have a potentially unbounded number of instances; one for each compilation phase (run-time, compilation time, compilation-compilation time, and so on). Implementing this is rather tricky if you want to do it efficiently.
At the moment, BH does not implement the syntactic tower; there is only one set of globals. Because of this, macros using global state become quite fragile. That's why syntax-rules is the recommended way of writing macros; it's impossible to run into these problems if you use them. Also, if you need more powerful macros, you can always use sc-macro-transformer (syntactic closure macros).
I have found a way to implement the syntactic tower in a way that doesn't inhibit the performance of the code after it's macro expanded, but it's somewhat complex and I haven't found the time to do it yet. It's rather high on the to do list though.
/Per