upvote
> I think a more accurate description is that lisp code is just cons cells and cons cells is both how we write the code and how the runtime itself implements lists. So there’s basically no distinction between a lisp list and the text representation of the source.

Heresy I suppose, but doesn't feel (to me) like it "specifically" has to be cons cells, as long as it's a "list" of some sort, regardless of the specific type of list, while I'd say "cons cells" is a specific implementation of a list, famously implemented by Common Lisp and similar lisps.

Besides that I agree with you, the code you write and the code the compiler uses is the same, that's why it gets easy to edit with code itself. Rust and similar don't have this feature at all, it's very different experience writing macros with lots of special syntax, compared to just writing "normal" code doing the same sort of operations. "Doing a loop of X" isn't the same inside of a normal runtime function body, as when you want to do a loop of arguments for the function signature in a macro, as just one simple example.

Not to mention in Rust you have two different types of macros, declarative vs procedural macros, already speaking to that the entire concept of homoiconicity isn't there. You want it to be easy to implement a read, evaluate, print and loop back workflow by passing native data through the entire chain, except parsing the initial user-input string into your AST (whatever shape that ends up being), which pretty-printed (basically) looks the same as the user-input.

reply
> Heresy I suppose, but doesn't feel (to me) like it "specifically" has to be cons cells, as long as it's a "list" of some sort

Yeah, "cons" is definitely a implementation detail. Maybe the central ideia is just "parenthesized s-expr".

reply
But this is just not true. An utf8 string is most definitely not a bunch of cons cells. Having a one-to-one correspondence is not the same thing, and one might argue that a rust code snippet and the corresponding AST object is just as arbitrarily far apart with a clean one-to-one correspondence.

So like, what's the material difference between the two? You have a parse and an eval in both cases

reply