I've been learning how to implement a Lisp interpreter in C, and decided to break it up into a tutorial series. Each part of the series is stand-alone and can be compiled and run (by clicking "Download Zip"). Open to any and all feedback, thanks in advance!
Here are the first 15 parts of the series, culminating in lambda:
https://gist.github.com/cellularmitosis/1106b185f8b34ae0e36afa5fbcd04a00
A proper Lisp interpreter tests whether an atom is the if symbol using eq comparison, not string. That's a very fundamental thing in Lisp, and is part of what makes Lisp dialects languages for "symbolic processing".
eq comparison just tests whether the left object and the right object are the same object. So in implementation terms, it might compare two machine words (which might be addresses).
In other words, if your objects are represented by pointers in C, then it's just:
where if_s is a variable or macro or whatever that refers to the if symbol. Somewhere in the code, at startup, that gets interned: When we read the input expression, the "if" text will also get passed to the intern function, which will return the same pointer. So then op_symp will be the same object as if_s, making the comparison true.The point is not just that this is faster, which it is: not scanning strings character by character when we wish to dispatch on symbols, and just comparing machine words is faster. The point is to be working with structured objects and not raw text, even when it comes to identifiers.
One nice thing about interned symbols is that if we create a brand new symbol object, then it is guaranteed to be unique (different from any other symbol and indeed any other object). That is true regardless of its name; even if its name clashes with that of an existing symbol, they are not the same object. In C terms, memory allocation always produces a new object that is different from any other object in the program.
Also note that the string "if" is not the value of the symbol if, but its name. Like in ANSI Lisp (symbol-name 'if) -> "IF". What we understand to be the value of a symbol is its binding to an object in some environment, which has no effect on its name.