3 ms·
I know so little about Smalltalk and its way of software development. A year ago, I read about VisualAge, and asked this question on the lisp subreddit: https:
by delish 9y ago
I know so little about Smalltalk and its way of software development. A year ago, I read about VisualAge, and asked this question on the lisp subreddit:
https://www.reddit.com/r/lisp/comments/4saada/curious_about_lisp_storing_code_and_state_in_image/ https://www.reddit.com/r/lisp/comments/4saada/curious_about_...
It has an interesting response from lispm. Having only worked in languages where the source is stored in files, it's hard for me to get a grasp on this kind of development. I catch rare glimpses of this. Here's another example, from http://dept-info.labri.u-bordeaux.fr/~strandh/Teaching/Langages-Enchasses/Common/Strandh-Tutorial/diff-scheme.html http://dept-info.labri.u-bordeaux.fr/~strandh/Teaching/Langa...
> A major problem with Scheme that does not exist in Common Lisp is that the Scheme language does not define an internal representation for programs, although to be fair, all Scheme implementations do.
> For instance, in Scheme, there is a difference between:
(define (f x y . (z))
...)
> which is syntactically illegal, and:
(define (f x y z)
...)
> which syntactically legal.
(You'll probably have to read that short section "Program/data equivalence"; I couldn't find the right excerpt)
Scheme code is stored in text files. Common Lisp code is a sequence of lisp objects. This is a strange difference to me; I'm an unexceptional web programmer. But it's "the very basis of the Common Lisp macro system, which uses Lisp data to represent and manipulate Lisp code." I am condemned to be intrigued!
- mikelevins 9y agoThe distinction is that Common Lisp source code is not text; it's Lisp values. What you see in a text file of "Lisp source code" isn't actually Lisp source code; it's a text serialization of Lisp source code. Other serializations are possible. As a practical matter, most of the time the distinction doesn't matter. You edit text files. Your Lisp reads the text files and the first thing it does with the contents is convert them to Lisp source code. The source code is then processed as you would expect. One place where the distinction matters is in macro processing: Lisp macro expansion operates on Lisp source code, not on text. If it operated on text, as, for example, C preprocessors do, then macro expansion would be a matter of string substitution. Instead, Lisp macro expanders operate on abstract syntax trees represented as convenient Lisp data structures, which means that macros are not limited to what can be conveniently done with simple string substitution. You have the full Lisp language available, operating on a convenient Lisp representation, to compute the expansion. More generally, when source code is represented as convenient data structures in the language, it's easier to build tools that operate on it. C compilers do not operate directly on text input; they convert it to internal data structures more convenient for the various stages of the compiler to work with. So does Lisp. The difference is that in a C compiler the representations used by the compiler are private implementation details, and in Lisp they are standard surface features of the language, available to every user.
- rjsw 9y agoI would want a Lisp VCS to preserve comments, which are not usually present in the deserialized form of "Lisp source code", so I don't really think your description helps here. I haven't used Xerox Lisp enough to remember whether the Common Lisp side did keep comments in a similar way to InterLisp-D.
- mikelevins 9y agoThere's no realistic danger of a Common Lisp implementation abandoning support for the text serialization of Lisp source code, because the reader is part of the language spec. That being the case, you can always count on support for Lisp text files, and therefore for comments stored in them. On the other hand, nothing in the standard forbids an implementation from keeping comments around in the image. Off the top of my head I don't know of an implementation that does it, but it might be a handy feature to have.
- lispm 9y agoComments in Interlisp weren't really magic. Basically the comment function * was taking unevaluated args as a list. An NLAMBDA. It just returned its arg. (* this is a comment in Interlisp) This means also comments could also only be used where they fit into the Lisp syntax and not changed the control flow. In Common Lisp: (defun comment (words) words) (defmacro § (&rest words) `(comment '(,@words))) (let ((a 20)) (cond ((< 0 a 10) (§ Only when A is between 0 and 10. This is a typical value.) (* a 0.1)) (t (§ a is not between 0 and 10) (* a 0.2)))) Now it would need a special pretty printer command, so that * comment lines would be layouted such that they are aligned fit on a line. * the position of the comment should stand out from the code. Interlisp had a pretty printer macro for it. It might be better to turn that into a reader macro, so that inside the comment one would then not be constrained by s-expression syntax.... Interlisp has also the feature to store/retrieve the comment text on demand from a file. Thus the comment text might not be needed to be present in the image itself.
- skybrian 9y agoIt might be interesting to compare how the error locations are reported, particularly when macros are involved. A typical AST can generate a file, line, and character offset for each node (at least), for printing errors. But if you don't have line numbers, there must be some alternative? Racket has "syntax objects" to handle this [1]. [1] https://docs.racket-lang.org/guide/stx-obj.html https://docs.racket-lang.org/guide/stx-obj.html
- jsnell 9y agoYou have the compiler use a special reader which records the source locations of each form in e.g. a hash table. When compiling a specific source, look it up in the hash table to get a source location mapping. There's a couple of downsides to this: - This only works when the reader returns unique objects. It's possible to track the location of a cons cell, but it's not possible to do it for any specific use of a symbol or a integer. - CL macros can do arbitrary transformations on the data. If those transformations involve loss of object identity, the tracking breaks down. (E.g. code-walking macros will often end up doing spurious copies, and cause unnecessary loss of source location mappings).
- arnsholt 9y agoWorking with Smalltalk is pretty cool. I sometimes say that the image-based part of Smalltalk is like Lisp, but done right, because the state of the code in your image and the state of the code in your source files can't ever get out of sync; the IDE is the image. It's also quite interesting from a language design perspective. For example, the syntax is mega-minimal (it's called Small talk for a reason!). The syntax can be summed up as: - A small handful of reserved words (self, true, false, nil, and one or two rarer cases that escape me ATM). - Local variable declarations. - Message calls on objects (what other languages usually call methods). Either unary calls "anObject unaryMethod" (a no-arg method), keyword calls "anObject withFoo: someObject withBar: anotherObject" (equivalent to anObject.method(foo, bar)", and binary calls "anObject + anotherObject" (single arg methods, written with infix syntax). - A syntax for lambda closures, called blocks in Smalltalk "[:a :b | $code ]", basically equivalent to (lambda (a b) $code). - Statements are terminated with a period. - "^foo" returns foo from a method. - The semi-colon is used for calling a sequence of methods on the same invocant (a better way to do fluent interfaces, basically). From these pieces everything else is constructed. There's no reserved syntax for things like conditionals or loops. For example, a conditional works like this "condition ifTrue: [ $trueCode ] ifFalse: [ $falseCode ]" which is just plain Smalltalk. The implementation is simply that the Boolean type has two subclasses True and False, and the implementation of the ifTrue:ifFalse: method calls the true code in True and the false code in False. Dead simple! Loops and exception handling are done similarly by calling methods on blocks.
- lispm 9y ago> I sometimes say that the image-based part of Smalltalk is like Lisp, but done right, because the state of the code in your image and the state of the code in your source files can't ever get out of sync; the IDE is the image. That's what Interlisp did too. Particular Interlisp-D and its later version Medley.
- arnsholt 9y agoOh, neat! I guess I shouldn't be surprised that advanced Lisp systems from that era did this kind thing as well. The Lisp and Smalltalk systems of that era really are something, even compared to modern development environments. Which is especially impressive when you consider the limitations they were working within.