What is the difference and the relation between the Lisp interpreter and the Lisp image? Can they be used as synonoms? - lisp

I noticed some people using the terms as if they were synonoms.
For instance, in the same scenario, I heard "add this function to the lisp image evaluating it" and "eval this function into the Lisp interpreter to use it later".
However, I am not sure the use is technically precise. Thus, the question.

These are two orthogonal concepts. Let’s start from the usually comprehensive Common Lisp Glossary:
Lisp image n. a running instantiation of a Common Lisp implementation. A Lisp image is characterized by a single address space in which any object can directly refer to any another in conformance with this specification, and by a single, common, global environment.
So the key idea is that an image is a set of mutually referring Lisp objects (functions and data) that can be “called” or “accessed” during the execution of a program.
The way in which a Common Lisp program is executed depends instead from the way in which a system is implemented. It could be executed by compilation in machine language, for instance, or through some form of interpretation (or even a mix of the two). So a Lisp interpreter is just a particular way in which an implementation is done (and in the current Common Lisp systems there are many different ways to implement the language).

Image
"Image" is a file on disk.
"Add a function to the image"
means evaluate the function and save the image, so the function if immediately available on the next invocation.
REPL
"Interpreter" is (usually) a wrong level of abstraction; one should use
"REPL" instead. E.g., SBCL does not have an interpreter at all (everything is always compiled) but this is not a detail that is relevant to this topic.
"eval this function into the Lisp interpreter to use it later"
means evaluate the function in the current REPL and use it in the same process (i.e., it is available until Lisp is restarted).

An image is a copy of a Lisp heap written to disk (or another secondary storage). The Lisp heap is the memory for data storage in RAM of a computer. To write a Lisp heap to an image, the running Lisp is stopped and the memory is dumped to disk. Then the Lisp is either resumed or quit.
The image can be used to restore the heap upon starting a new Lisp. That's usually faster than starting a fresh Lisp and then loading the corresponding software.
A Lisp interpreter is a program which executes Lisp programs from source. Many Lisp implementations don't use an interpreter, but they execute compiled Lisp code, typically Lisp code compiled to native machine code.

Related

The concept of Self-Hosting

So I'm developing a small programming language, and am trying to grasp around the concept of "Self-Hosting".
Wikipedia states:
The first self-hosting compiler (excluding assemblers) was written for Lisp by Hart and Levin at MIT in 1962. They wrote a Lisp compiler in Lisp, testing it inside an existing Lisp interpreter. Once they had improved the compiler to the point where it could compile its own source code, it was self-hosting.
From this, I understand that someone had a Lisp interpreter, (lets say in Python).
The Python program then reads a Lisp program which in turn can also read Lisp programs.
By the term, "Self-Hosting", this surely can't mean the Python program can cease to be of use, because removing that would remove the ability to run the Lisp program which reads other Lisp programs!
So by this, how does a program become able to host itself directly on the OS? Maybe I'm just not understanding it correctly.
In this case, the term self-hosting applies to the Lisp compiler they wrote, not the interpreter.
The Python Lisp interpreter (as in your example) would take Lisp source as input, and execute it directly.
The Lisp compiler (written in lisp) can take any Lisp source as input and generate a native machine binary[1] as output (which could then run without an interpreter).
With those two pieces, eliminating Python becomes feasible. The process would go as follows:
python.exe lispinterpret.py lispcompiler.lisp -i lispcompiler.lisp -o lispcompiler.exe
We ask Python to interpret a lisp program from source (lispcompiler.lisp), and we pass lispcompiler.lisp itself as input. lispcompiler.lisp then outputs lispcompiler.exe as output, which is a native machine binary (and doesn't depend on Python).
The next time you want to compile the compiler, the command is:
lispcompiler.exe -i lispcompiler.lisp -o lispcompiler2.exe
And you will have a new compiler without the use of Python.
[1] Or you could generate assembly code, which is passed to an assembler.

Is LISP a compiled or interpreted language?

I know there is no such thing, strictly speaking, as a compiled or interpreted language.
But, generally speaking, is LISP used to write scripts like Python, bash script, and batch script?
Or is it a general purpose programming language like C++, JAVA, and C#?
Can anyone explain this in simple terms?
Early versions of Lisp programming language and Dartmouth BASIC would be examples interpreter language (parse the source code and perform its behavior directly.). However, Common lisp (Current version) is a compiler language.
Note that most Lisp compilers are not Just In Time compilers. You as a programmer can invoke the compiler, for example in Common Lisp with the functions COMPILE and COMPILE-FILE. Then Lisp code gets compiled.
Additionally most Lisp systems with both a compiler and an interpreter allow the execution of interpreted and compiled code to be freely mixed.
For more details check here
Lisp is a compiled general purpose language, in its modern use.
To clarify:
“LISP” is nowadays understood as “Common Lisp”
Common Lisp is an ANSI Standard
There are several implementations of Common Lisp, both free and commercial
Code is usually compiled, then loaded into an image. The order in which the individual parts/files of an entire system are compiled and loaded is usually defined through a system definition facility (which mostly means ASDF nowadays).
Most implementations also provide a means for loading source code when started. Example:
sbcl --load 'foo.lisp'
This makes it also possible to use lisp source files as “scripts”, even though they will very likely be compiled before execution.
Traditionally, LISP can be interpreted or compiled -- with some of each running at the same time. Compilation, in some cases, would be to a virtual machine like JAVA.
LISP is a general purpose programming language, but rarely used as such anymore. In the days of microcoded LISP machines, the entire operating system, including things like network, graphics and printer drivers, were all written in LISP itself. The very first IMAP mail client, for example, was written entirely in LISP.
The unusual syntax likely makes other programming languages, like Python, more attractive. But if one looks carefully, you can find LISP-inspired elements in popular languages like Perl.

Might this permanently and accidentally overwrite the compiler's own functionality?

So I was writing my own function and I called it make-list and I got this from debugger:
The function MAKE-LIST is predefined in Clozure CL.
[Condition of type SIMPLE-ERROR]
Restarts:
0: [CONTINUE] Replace the definition of MAKE-LIST.
Fine, but what if I had accidentally chosen option 0?? Would my compiler be broken and forever have the wrong definition of an internal function, as I would have replaced it?
Only your currently running image would be broken, in which case you can restart CCL to restore it.
The only way to do permanent damage is to save the image, and chose to overwrite the original image file.
Many Lisp systems are written in Lisp themselves.
Clozure CL is such an example. Clozure CL is written in Clozure CL (with some C and assembler). Clozure CL can compile itself.
Thus many/most Common Lisp functions in Clozure CL are written in Clozure CL. So it needs some kind of a switch, where it allows to define or redefine built-in functionality. So there is definitely a way to edit the implementation's source code and change things. It would be best that your definitions are 'correct', so that the functioning of the Lisp system is not compromised. Keep in mind that redefinitions typically do not have an effect on inlined functions or on already expanded macros.
Now, if we as typical programmers use Clozure CL, some packages are protected and redefining the symbols are not allowed and an error is signaled. But you can continue and then change internal functions. As always in many Common Lisp, they are wide open for changes, but this comes with the responsibility for you as the programmer to do the right thing.
If you change a Lisp-internal function, there a some ways to leave permanent damage:
saving an image and using that later
using it to recompile CCL itself or parts of it
you could compile a file and somehow the generated code could be different than with the original compiler
you could compile a file and somehow the generated code includes an inlined version of the changed Lisp function
if one loads such a file, it could be automatically via some init file, it contains the changes and the changed code will be a part of the then currently running Lisp.

LISP 1.5 How lisp is like a machine language?

I wish that John McCarthy was still alive, but...
From LISP 1.5 Programmer's Manual :
LISP can interpret and execute programs written in the form of S-
expressions. Thus, like machine language, and unlike most other higher
level languages, it can be used to generate programs for further
execution.
I need more clarification about how machine language can used to generate programs and how Lisp can do it?
All that is saying is that machine code can directly write machine instructions to memory and jump to those instructions to execute them; this is the basis of many attack vectors to break into software, in fact.
The point is, when you're writing machine code, it's easy to generate machine code. But when you're writing in a compiled language like C, you can't just generate C code at run time and then execute it - unless your program includes a C compiler.
Lisp - and, these days, many other languages, especially "scripting languages" like Perl, Python, Ruby, Tcl, Javascript, and command shells - have the ability to execute code that is generated at runtime. In Lisp, since code and data have the same structure, this is usually less work than it is in the other languages, where the code to be evaluated is generally a string that has to be parsed. (Though Perl has the ability to eval a block instead of a string, which lets the compiler do the parsing ahead of time for literal code.)
A machine language can alter itself while running. The last assembly programming i did was for MS DOS and resident program that i used to run before testing other programs. When my program misbehaved, a keystroke switched to the resident program and could peek into the running program and alter it directly before resuming. It was quite handy since I didn't have a debugger.
LISP had this from the very beginning since it was originally interpreted. You could change the definition of a function while you were running and the whole langugage was always available at runtime, even eval and define. When it started getting compiled it wasn't compiled like Algol, but partially, allowing for interpreted and compiled code to intermix at the same time. The fact that its code structure was list structure and that symbols are a data type contributed to this.
Last interview I saw with McCarthy he was asked about what he thought of modern programming languages (Not LISP family but the Algol family language Ruby, that is said to be influenced by LISP), and before answering he asked if they could represent code as data (like list structure). Since it didn't, Ruby is still behind what LISP was in the 60s in his opinion.
Many new programming languages are emerging in the Algol family and some of the most promising ones, like Perl6 and Nemerle, are getting closer to the features LISP had in the 60s.
Machine language programs can fill memory regions with arbitrary bytes. Then they can just jump to the start of such region which will thus get executed right away.
Lisp language programs can easily create arbitrary S-expressions in memory, using cons. Then they can just call eval on these S-expressions to evaluate (interpret) them.
High level languages programs can easily fill memory regions with characters representing new code in the language's syntax. But they can not run such a code.

What is a Lisp image?

Essentially, I would like to know what a Lisp image is? Is it a slice of memory containing the Lisp interpreter and one or more programs or what?
The Lisp image as dumped memory
The image is usually a file. It is a dump of the memory of a Lisp system. It contains all functions (often compiled to machine code), variable values, symbols, etc. of the Lisp system. It is a snapshot of a running Lisp.
To create an image, one starts the Lisp, uses it for a while and then one dumps an image (the name of the function to do that depends on the implementation).
Using a Lisp image
Next time one restarts Lisp, one can use the dumped image and gets a state back roughly where one was before. When dumping an image one can also tell the Lisp what it should do when the dumped image is started. That way one can reconnect to servers, open files again, etc.
To start such a Lisp system, one needs a kernel and an image. Sometimes the Lisp can put both into a single file, so that an executable file contains both the kernel (with some runtime functionality) and the image data.
On a Lisp Machine (a computer, running a Lisp operating system) a kind of boot loader (the FEP, Front End Processor) may load the image (called 'world') into memory and then start this image. In this case there is no kernel and all that is running on the computer is this Lisp image, which contains all functionality (interpreter, compiler, memory management, GC, network stack, drivers, ...). Basically it is an OS in a single file.
Some Lisp systems will optimize the memory before dumping an image. They may do a garbage collection, order the objects in memory, etc.
Why use images?
Why would one use images? It saves time to load things and one can give preconfigured Lisp systems with application code and data to users. Starting a Common Lisp implementation with a saved image is usually fast - a few milliseconds on a current computer.
Since the Lisp image may contain a lot of functionality (a compiler, even a development environment, lots of debugging information, ...) it is typically several megabytes in size.
Using images in Lisp is very similar to what Smalltalk systems do. Squeak for example also uses an image of Smalltalk code and data and a runtime executable. There is a practical difference: most current Lisp systems use compiled machine code. Thus the image is not portable between different processor architectures (x86, x86-64, SPARC, POWER, ARM, ...) or even operating systems.
History
Such Lisp images have been in use since a long time. For example the function SYSOUT in BBN Lisp from 1967 created such an image. SYSIN would read such an image at start.
Examples for functions saving images
For an example see the function save-image of LispWorks or read the SBCL manual on saving core images.
Several language implementations use an 'image' to store ''everything'' that is there
in the current context. This image may several abstraction layers of compilation ( i.e.
an intermediate parse level, an intermediate byte code, native op codes ). Loading this
image will be much faster than compiling all the source files. It's very much like the
hibernate feature, at a program level.
For example , if your-lisp-implementation uses a image, than first you ( or the compiler
vendor will ) boot strap an image, and save it.
Then you have two options: (1) either load your lisp file everytime you invoke lisp or (2) load all your lisp, and save the image , and use this image
Hope that helps
In general, it's the storage part of the lisp process (that is, all "lisp" functions and data), but no parts of the underlying lisp binary. On the plus side, this gives a fast start-up, since there's (essentially) no book-keeping to be done on loading the image, everything is just there. On the other hand, it means any open files, sockets and what-have-you are missing, so saving images as some sort of check-pointing will require a bit of implementation to make it work.