Earlier quoted context omitted.
Yea, that's a weird statement, however a better one is that Smalltalk doesn't need macros because it has a clean syntax for lambas that remove a common use for macros, hiding boilerplate use of Lisp's lambda. Beyond that, Smalltalk isn't file based, you don't edit some version of the code that gets compiled (and macro expanded) into some runtime version of the code you can only see through introspection; rather in Sm…
> Beyond that, Smalltalk isn't file based, you don't edit some version of the code that gets compiled (and macro expanded) into some runtime version of the code you can only see through introspection; rather in Smalltalk you're actually editing the runtime version in a running image. That's not really true. Smalltalk is text-based, too, but hides it behind an integrated source management system. When you edit a metho…
Lisp, Smalltalk, and the Power of Symmetry (2014)
21–30 of 62 posts
Re: Lisp, Smalltalk, and the Power of Symmetry (2014)
#22Earlier quoted context omitted.
> Smalltalk isn't file based, you don't edit some version of the code that gets compiled (and macro expanded) […] Macros simply wouldn't fit into Smalltalk in any meaningful way […] You speak as if “macros” means “macros as implemented in the C preprocessor”. Lisp macros, as I understand it, operate on the parsed syntax tree, not on the file text level, and are expanded at runtime, not compile time.
The key to understanding macros is to be quite clear about the distinction between the code that generates code (macros) and the code that eventually makes up the program (everything else). When you write macros, you're writing programs that will be used by the compiler to generate the code that will then be compiled. Only after all the macros have been fully expanded and the resulting code compiled can the program a…
Remember, a Lisp interpreter interprets Lisp source as data. Not byte code. Unlike Python, Java, Smalltalk, ... which all have popular implementations which compile to byte code and execute that byte code in a byte code interpreter, aka virtual machine.
Let's use a Lisp interpreter, here from LispWorks:
We define a primitive MY-IF macro. It expands into a simple IF use. But the macro will also count the number of macro expansions.
CL-USER 46 > (defparameter *myif-counter* 0)
*MYIF-COUNTER*
CL-USER 47 > (defmacro my-if (c a b)
(incf *myif-counter*)
`(if ,c ,a ,b))
MY-IF
LispWorks can trace macros, too. CL-USER 48 > (trace my-if)
(MY-IF)
Now a simple function which uses our macro: CL-USER 49 > (defun fac (n)
(my-if (= 1 n)
1
(* n (fac (1- n)))))
FAC
Now we use it and we will see the trace information for the macro use: you see the incoming form and the result form. CL-USER 50 > (fac 2)
0 MY-IF > ...
>> COMPILER::FORM : (MY-IF (= 1 N) 1 (* N (FAC (1- N))))
>> COMPILER::ENVIRONMENT : #)) benv NIL tenv NIL decl NIL>
0 MY-IF ...
>> COMPILER::FORM : (MY-IF (= 1 N) 1 (* N (FAC (1- N))))
>> COMPILER::ENVIRONMENT : #) fenv ((#:SOURCE-LEVEL-ENVIRONMENT-MARKER . #) (#:FUNCTOR-MARKER . #)) benv NIL tenv NIL decl NIL>
0 MY-IF ...
>> COMPILER::FORM : (MY-IF (= 1 N) 1 (* N (FAC (1- N))))
>> COMPILER::ENVIRONMENT : #)) benv NIL tenv NIL decl NIL>
0 MY-IF ...
>> COMPILER::FORM : (MY-IF (= 1 N) 1 (* N (FAC (1- N))))
>> COMPILER::ENVIRONMENT : #) fenv ((#:SOURCE-LEVEL-ENVIRONMENT-MARKER . #) (#:FUNCTOR-MARKER . #)) benv NIL tenv NIL decl NIL>
0 MY-IF
Let's see how often our macro function has been used to expand code: CL-USER 51 > *myif-counter*
4Re: Lisp, Smalltalk, and the Power of Symmetry (2014)
#23Earlier quoted context omitted.
> Smalltalk isn't file based, you don't edit some version of the code that gets compiled (and macro expanded) […] Macros simply wouldn't fit into Smalltalk in any meaningful way […] You speak as if “macros” means “macros as implemented in the C preprocessor”. Lisp macros, as I understand it, operate on the parsed syntax tree, not on the file text level, and are expanded at runtime, not compile time.
The key to understanding macros is to be quite clear about the distinction between the code that generates code (macros) and the code that eventually makes up the program (everything else). When you write macros, you're writing programs that will be used by the compiler to generate the code that will then be compiled. Only after all the macros have been fully expanded and the resulting code compiled can the program a…
Re: Lisp, Smalltalk, and the Power of Symmetry (2014)
#24I have been programming professionally in Common Lisp (off and on) since the 1980s but there is something equally magical about Smalltalk. I have often thought that Smalltalk could be the language I use after I retire (I am in my 60s and I will probably stop working in about ten years).
Re: Lisp, Smalltalk, and the Power of Symmetry (2014)
#25Wonderful article! "Smalltalk, like Lisp, runs in the same context it’s written in." I have been programming professionally in Common Lisp (off and on) since the 1980s but there is something equally magical about Smalltalk. I have often thought that Smalltalk could be the language I use after I retire (I am in my 60s and I will probably stop working in about ten years).
Re: Lisp, Smalltalk, and the Power of Symmetry (2014)
#26Earlier quoted context omitted.
The key to understanding macros is to be quite clear about the distinction between the code that generates code (macros) and the code that eventually makes up the program (everything else). When you write macros, you're writing programs that will be used by the compiler to generate the code that will then be compiled. Only after all the macros have been fully expanded and the resulting code compiled can the program a…
Is it not the fact that macros can be defined and, more importantly, redefined at runtime? If so, would that not mean that macros must also be expanded at runtime?
If you have interpreted Lisp code, then the code can use the new macro automagically.
Re: Lisp, Smalltalk, and the Power of Symmetry (2014)
#27Earlier quoted context omitted.
No, this is incorrect. The syntax and the AST must be isomorphic for a language to be homoiconic. It's not enough to expose the compiler/AST as a first-class library. Wikipedia has a nice entry on this. In short, "homoiconicity is where a program's source code is written as a basic data structure that the programming language knows how to access." [1]: https://en.wikipedia.org/wiki/Homoiconicity
According to that page, the term was introduced by the designer of something called TRAC, who used it to denote the idea that the program is stored in the memory in the same form in which the user enters it, which allows it to be inspected and changed. Nothing about ASTs.
TRAC is lots of fun. I read about it in Nelson's book, Computer Lib/Dreams, when I was a freshman at Illinois. That spring, my Dad bought an Altair and I wrote a version of Trac for it, in assembly. Had support for bignum arithmetic, in ASCII :-)
Later, when I learned about tail recursion, I was happy to figure out that my implementation was indeed properly tail recursive.
Re: Lisp, Smalltalk, and the Power of Symmetry (2014)
#28That's what Lisp systems do too. Program elements like classes, functions, methods, symbols, ... are first class objects. With something like CLOS you have a similar level of object-oriented meta-programming capabilities.
Many Lisp systems offer additionally to execute Lisp data using a Lisp interpreter and Lisp has a simple data representation for Lisp programs: Lisp data.
Smalltalk OTOH uses text as source code and usually a compiler to byte-code.
> because Lisp source code is expressed in the same form as running Lisp code
Only if you use a Lisp interpreter. Otherwise the running Lisp code might be machine code or some byte code.
> Smalltalk goes one further than Lisp: it’s not that Smalltalk’s source code has no syntax so much as Smalltalk has no source code.
That's a misconception. Smalltalk has source code. As text. It's just typically managed by the integrated development environment.
It's actually Lisp which goes further than Smalltalk, because Lisp has source as data and can use that in Lisp interpreters directly for execution.
Re: Lisp, Smalltalk, and the Power of Symmetry (2014)
#29Earlier quoted context omitted.
Yea, that's a weird statement, however a better one is that Smalltalk doesn't need macros because it has a clean syntax for lambas that remove a common use for macros, hiding boilerplate use of Lisp's lambda. Beyond that, Smalltalk isn't file based, you don't edit some version of the code that gets compiled (and macro expanded) into some runtime version of the code you can only see through introspection; rather in Sm…
> Beyond that, Smalltalk isn't file based, you don't edit some version of the code that gets compiled (and macro expanded) into some runtime version of the code you can only see through introspection; rather in Smalltalk you're actually editing the runtime version in a running image. That's not really true. Smalltalk is text-based, too, but hides it behind an integrated source management system. When you edit a metho…
What I said it true practically speaking, you're getting into implementation details that don't make a practical difference. Lisp and Smalltalk are both image based systems, but Smalltalk'ers actually work on the running live image all of the time, they aren't ever booting from the sources file nor are they ever editing it manually (excluding the one file based GNU Smalltalk), it's pared with a changes file to enable the IDE to expose the current source of a method but those are hidden implementation details whereas I'm talking about the abstraction presented to the programmer. Lispers "can" do this as well, and sometimes do, but Lisp has a much more standard general workflow of editing files that are then read and launched to create/patch a runtime image it's not the normal worflow to work entirely in the REPL which is essentially what Smalltalk'ers do.
Consider the difference, what Smalltalker's see in their code browsers is a text version of what's actually running; if they had macros, which are nothing more than code generators, they'd be seeing is the macro expansion rather than the original source call to the macro. Certainly Lispers "can" do this as well, they can macro expand something to see what's actually running but as their primary mode is editing the original source they're accustomed to seeing the macro unexpanded, they might define an accessor like
(name :accessor person-name
:initform 'bill
:initarg :name)
And from experience know that an accessor is a getter, setter, and backing instance variable but they don't see those things in their editors, they just know they'll exist at runtime; whereas a Smalltalker is accustomed to looking at the runtime where he actually sees the getter, setter, and and backing instance variable.Macros just don't fit into Smalltalk; they've been added before, people keep trying it, and it just doesn't fit and so doesn't catch on.
Re: Lisp, Smalltalk, and the Power of Symmetry (2014)
#30Earlier quoted context omitted.
> Beyond that, Smalltalk isn't file based, you don't edit some version of the code that gets compiled (and macro expanded) into some runtime version of the code you can only see through introspection; rather in Smalltalk you're actually editing the runtime version in a running image. That's not really true. Smalltalk is text-based, too, but hides it behind an integrated source management system. When you edit a metho…
I'm well aware, I've programmed in Pharo daily for a decade; I Smalltalk for a living. What I said it true practically speaking, you're getting into implementation details that don't make a practical difference. Lisp and Smalltalk are both image based systems, but Smalltalk'ers actually work on the running live image all of the time, they aren't ever booting from the sources file nor are they ever editing it manually…
You edit the source code via the IDE. Just like in Lisp systems. It's just that the IDE works differently.
> Smalltalk'ers actually work on the running live image all of the time
That's the dominant way to work in Lisp, too. My Lisp Machine even runs it as an OS. I use LispWorks for development on my Mac - the IDE is the running Lisp system.
> it's not the normal worflow to work entirely in the REPL
Actually that's the default mode. If you develop Lisp code with SLIME / GNU Emacs, it talks to a live Lisp system.
> if they had macros, which are nothing more than code generators, they'd be seeing is the macro expansion rather than the original source call to the macro.
That's not how Lisp works. Macros are not simple code generators, where the workflow would be write macro code, expand that, and use the expanded code. The Lisp developer is not generating code and working with that generated code. The generated code is usually hidden and generated by the Lisp system on demand/incrementally for internal use.
> And from experience know that an accessor is a getter, setter, and backing instance variable but they don't see those things in their editors, they just know they'll exist at runtime; whereas a Smalltalker is accustomed to looking at the runtime where he actually sees the getter, setter, and and backing instance variable.
In this case the Lisp developer sees the generated objects: the getter, setter slot definitions. What the Lisp developer usually does not look at is the code generated by the macros. It might be useful to have source code for the macro forms and being able to edit them, but it is usually not done in Lisp. There are many macros, where there are no generated objects and the resulting code is extremely complex and large. Thus it would not make sense at all to present this code or edit this code...
> don't see those things in their editors, they just know they'll exist at runtime
I'll see it in the runtime. The introspective capability tells me that it is there. If I want to edit them, I would then go back to the source. For example when I call (ed 'foobar) to edit the accessor foobar, it would open up the defclass form in the editor. Some Lisp systems (like LispWorks)also offer the link back from the objects to the macro form which was responsible for creating them. What I usually don't want to see is the generated code, since that's not fit for human consumption.
> Macros just don't fit into Smalltalk; they've been added before, people keep trying it, and it just doesn't fit and so doesn't catch on.
Because they difficult to integrate into Smalltalk and its idea of an IDE. Macros add a lot complexity to the system and how the developers are using it. They offer code manipulation and the price is losing a direct connection of the object code / the objects from the source code.