Stuff like this is frankly why so many programmers shy away from lisp and s-expression based languages.
Stuff like this is frankly why so many programmers shy away from lisp and s-expression based languages.
That's the popular slogan, but there'a actually quite a lot more to it than that. After all, strings are data too, and C programs are represented as strings, so "code is data" in C too. But that is obviously missing the point.
What's really going on is that, in Lisp, code is a particular kind of data, specifically, it's a tree rather than a string. Therefore, some (but not all) of the program's structure is represented directly in the data structure in which it is represented, and that makes certain kinds of manipulations on code easier, and it makes other kinds of manipulations harder or even impossible. But (and this is the key point) the kinds of manipulations that are easier are the kind you actually want to do in general, and the kind that are harder or impossible are less useful. The reason for this is that the tree organizes the program into pieces that are (mostly) semantically meaningful, whereas representing the program as a string doesn't. It's the exact same phenomenon that makes it easier to manipulate HTML correctly using a DOM rather than with regular expressions.
I ask myself based on this world view if there are useful other representations beyond the popular choices of lists and strings. Apparently, lists (like in lisp) are already so universal that they can represent any kind of structural data.
In fact, there is no one "killer feature". It's a confluence of lots of little details. Two of the details that turn out to matter most is having symbols, and not having comas as separators in the surface syntax. Those two things are the difference between S-expressions:
(defun foo (x y) (baz (bar x) (bing y)))
and JSON, which can represent the exact same thing:
['defun', 'foo', ['x', 'y'], ['bar', 'x'], ['bing', 'y']]]
but obviously you wouldn't want to write your code like that.
You might be able to improve on linked lists as a code representation. You could, for example, use vectors instead of linked lists (i.e. cons cells) or maybe associative maps (i.e. dictionaries) as a core data structure. It's not hard to try out things like this in Lisp, so if you really want to know what happens, just grab yourself a Lisp interpreter (or even better, write one yourself) and try it.
Mind. Blown. Your whole comment is incredible. I've never thought about it this way or realized what the value proposition was. Thanks!
http://www.defmacro.org/ramblings/lisp.html
If not then people might enjoy a deeper dive into this kind of thing! For anybody who's not read it - since it's pretty long I'll try and sum it up with a quote from about 2/3 of the way down:
"Lisp is executable XML with a friendlier syntax"
This bit always comes to mind when I think of lisp and "code as data / data as code".
I thought the point in lisp was that the syntax for non-code data and code are the same so treating code as data (and thinking about code as data) is easier than in many other programming languages.
I'd just like to interject for a moment.
To add on to what you have said: More precisely, Lisp programs are just lists; and in Lisp lists are first-class data structures (that is, there is a ton of functions for working with list). Thus, in Lisp, Lisp programs are first-class data structures as well.
I do it because the editors are terrible.
I love s-expressions, but it will be a cold day in hell before I waste more of my life with Emacs, Vim or DrRacket.