|  | Edit commands in Command Line Interpreters |  | |
| | | Richard Harter |  |
| Posted: Fri Aug 15, 2008 4:50 am Post subject: Edit commands in Command Line Interpreters |  |
| |  | |
In most programming languages source code is in a file or files. The file(s) are either fed to a compiler or an interpreter; the user does not alter the source code during execution.
In some languages, e.g., command line interpreters and shell programs, the user can also enter code interactively. There are some extra features that useful for interactive mode. Thus:
(a) It is useful to be able to silently enter blocks of code, i.e., the interpreter does not execute the lines until an entire block has been entered.
(b) It is useful to be able to edit code on the fly, i.e., edit blocks of code as they are being entered.
(c) It is useful to be able to edit code that has already been entered and executed.
One way to do this is to run the interpreter within an editor, e.g., emacs. An alternative is to include editing commands directly within the language. Does anyone have opinions about or experience with the latter option?
Richard Harter, cri@tiac.net LINK LINK Save the Earth now!! It's the only planet with chocolate. |
| |
| | | Pascal J. Bourguignon |  |
| Posted: Fri Aug 15, 2008 9:02 am Post subject: Re: Edit commands in Command Line Interpreters |  |
| |  | |
cri@tiac.net (Richard Harter) writes:
| Quote: | In most programming languages source code is in a file or files. The file(s) are either fed to a compiler or an interpreter; the user does not alter the source code during execution.
In some languages, e.g., command line interpreters and shell programs, the user can also enter code interactively. There are some extra features that useful for interactive mode. Thus:
(a) It is useful to be able to silently enter blocks of code, i.e., the interpreter does not execute the lines until an entire block has been entered.
(b) It is useful to be able to edit code on the fly, i.e., edit blocks of code as they are being entered.
(c) It is useful to be able to edit code that has already been entered and executed.
One way to do this is to run the interpreter within an editor, e.g., emacs. An alternative is to include editing commands directly within the language. Does anyone have opinions about or experience with the latter option?
|
You have to see it in terms of virtual machine.
Virtual machines are implemented over virtual machines.
(Some virtual machines are implemented over silicium, but we programmers don't get to see them usually: it's only Intel's engineers who program the ix86 virtual machine in microcode over their silicium who see it). Yes, the ix86 in current process is actually a virtual machine, that gets compiled Just In Time by the processor.
Ok so you have this ix86 virtual machine, and over it is implemented another virtual machine, the OS virtual machine. Let's say the unix virtual machine to be concrete.
On this unix virtual machine, you have some other virtual machines, like the emacs editor (which itself contains at least two virtual machines: the lisp VM, and the editor itself). And of course, you have virtual machines such as REPL environments.
A compiler is not really a virtual machine, it translates files intended for one virtual machine to files intended for another virtual machine. If you consider a compiler embedded in an IDE, you could say that you have a C virtual machine (instead of a pure unix virtual machine, characterized by the part of the underlying virtual machine it exports and its syscalls).
What I call REPL environments, are those virtual machines that have a Read-Eval-Print-Loop that allows you to modify very easily the program loaded in the virtual machine. It can use either an interpreter or a compiler (or both) to translate the text you type in into a program executable by the virtual machine it implements.
Ok, so now the important question is where persistence occurs.
At the ix86 level, there is no persistance (there may be some persistent PRAM, or you could consider the BIOS EEPROM as some persistent storage, but it is not usually used as thus for user programs).
Persistence is implemented at the OS level, by the use of persistente storage memory such as hard disks, and the implementation of a file system. Some OS implement persistence of user objects without a file system (cf. EROS LINK).
Above a unix OS, all persistence is implemented using the unix file system. Another important characteristic is that processes ARE NOT persistent in unix. (They may be made persistent, and even migrable (in clusters), but this is hard and rare). Because of the characteristics of the unix virtual machine (basically the characteristics you can see in a C virtual machine: no memory protection from one block of memory to the other, etc), programs on the unix virtual machine often have bugs and crash. Not having persistent process is a "protection" unix OS offers against its own defects. Your program crashes, the OS cleans up the process, and you can restart. As long as the program bug didn't erase or modify persistent data in the file system, you're OK. (And for the case of persistent data damage, you can always get back to your backups, you do have backups don't you).
Note another interesting characteristic of unix systems: when it runs out of memory (both RAM and swap), it starts to kill innocent processes 'at random'. Well sometimes, it choose rather a process with a big memory footprint, to kill the smallest number of processes.
Let's consider now a REPL virtual machine implemented over a unix virtual machine. When you modify the state of the REPL virtual machine, you modify the REPL virtual machine "image", that is, the memory the REPL virtual memory process uses. From within the REPL virtual machine, this change is persistent, but since it is actually stored inside the unix process memory, it is persistent only as long as the REPL virtual machine process runs. Since it can be killed easily just because of a bug in the implementation (rare when it's not implemented in C), or just because the unix virtual machines wants because it runs out of memory because of the other processes, and this REPL virtual machine process uses a lot of memory (as is often the case, since it has a whole world loaded, including compiler, interpreter, editor, and other tools in addition to the user programs), you can lose all that you stored in the REPL virtual memory image at random points (or just when you shut down the REPL virtual machine).
In this situation, it is worthwhile to rather edit the sources in an editor external to the virtual machine, and have it save the files in the unix virtual machine persistent store. (eg. a Common Lisp implementation with emacs, and possibly slime to have a direct communication between emacs and the CL implementation, in addition to the underlying virtual machine persistent storage).
Now of course, if the REPL virtual machine implements primitives to load and store files in the underlying virtual machine persistent store, you can also implement an editor inside the REPL virtual machine, and just load and save files from there, instead of from the emacs lisp virtual machine. (Examples are the Climacs or Hemlock editors running in a Common Lisp virtual machine).
However, when the REPL virtual machine has good introspective features, even this edit/save-file/load-file-in-REPL cycle becomes tedious. We want to go at the code that is stored inside the REPL virtual machine, and directly edit it in place. A prototypal example of this would be the Smalltalk browser. In this case, we modify directly the REPL virtual machine memory, and it is not persistent. We live dangerously! Happily often these REPL virtual machines can save their "image" to a file in the underlying virtual machine persistent storage, and when you boot one of these REPL virtual machines, you can specify what "image" file to load, in place of the default "image" file. This is wholesale persistence.
(Sometimes, the code entered is not kept in source form in the REPL virtual machine image. But usually it's easy to add the needed book-keeping. See for example for CL: LINK )
In the end, and given that emacs, either with its bare "inferior-lisp" mode plus some easily implemented commands, or with the full featured Slime package, can give the illusion of working within the Common Lisp image, (and more or less similarly for some other REPL virtual machines, if with perhaps less features), the question is whether you prefer to work with the powerful tools offered within emacs, or if you are satisfied by the editor in your REPL virtual machine. Personnaly, I never could use the Smalltalk editor. I would have had to implement an emacs in the Smalltalk image first.
-- __Pascal Bourguignon__ LINK
PLEASE NOTE: Some quantum physics theories suggest that when the consumer is not directly observing this product, it may cease to exist or will exist only in a vague and undetermined state. |
| |
| | | James Harris |  |
| Posted: Fri Aug 15, 2008 7:17 pm Post subject: Re: Edit commands in Command Line Interpreters |  |
| |  | |
On 15 Aug, 07:50, c...@tiac.net (Richard Harter) wrote:
| Quote: | In most programming languages source code is in a file or files. The file(s) are either fed to a compiler or an interpreter; the user does not alter the source code during execution.
In some languages, e.g., command line interpreters and shell programs, the user can also enter code interactively. There are some extra features that useful for interactive mode. Thus:
(a) It is useful to be able to silently enter blocks of code, i.e., the interpreter does not execute the lines until an entire block has been entered.
(b) It is useful to be able to edit code on the fly, i.e., edit blocks of code as they are being entered (c) It is useful to be able to edit code that has already been entered and executed.
One way to do this is to run the interpreter within an editor, e.g., emacs. An alternative is to include editing commands directly within the language. Does anyone have opinions about or experience with the latter option?
|
I used to work with PL1022 which is basically a database access language. It was fairly standard for us to write code that would write and execute other PL1022 code. After a while this way of working became quite familiar and not as confusing as might be expected. However, IIRC, we had to work that way largely because the language did not readily permit us to do what we wished to do directly.
I thus tend to think that
a) generating code from within code is associated with poor languages, b) even if the user enters the code on the fly the whole process sounds prone to lead to confusion.
So I cannot comment on the options you mention. Maybe if you could give a concrete example or two of where this all would be advisable it would be easier to see why the facility would be desirable....?
On the other hand are you thinking of something like Basic where interaction with the interpreter is via a command line?
-- James |
| |
| | | Richard Harter |  |
| Posted: Mon Aug 18, 2008 1:55 pm Post subject: Re: Edit commands in Command Line Interpreters |  |
| |  | |
On Fri, 15 Aug 2008 12:17:00 -0700 (PDT), James Harris <james.harris.1@googlemail.com> wrote:
| Quote: | On 15 Aug, 07:50, c...@tiac.net (Richard Harter) wrote: In most programming languages source code is in a file or files. The file(s) are either fed to a compiler or an interpreter; the user does not alter the source code during execution.
In some languages, e.g., command line interpreters and shell programs, the user can also enter code interactively. There are some extra features that useful for interactive mode. Thus:
(a) It is useful to be able to silently enter blocks of code, i.e., the interpreter does not execute the lines until an entire block has been entered.
(b) It is useful to be able to edit code on the fly, i.e., edit blocks of code as they are being entered (c) It is useful to be able to edit code that has already been entered and executed.
One way to do this is to run the interpreter within an editor, e.g., emacs. An alternative is to include editing commands directly within the language. Does anyone have opinions about or experience with the latter option?
I used to work with PL1022 which is basically a database access language. It was fairly standard for us to write code that would write and execute other PL1022 code. After a while this way of working became quite familiar and not as confusing as might be expected. However, IIRC, we had to work that way largely because the language did not readily permit us to do what we wished to do directly.
I thus tend to think that
a) generating code from within code is associated with poor languages, b) even if the user enters the code on the fly the whole process sounds prone to lead to confusion.
So I cannot comment on the options you mention. Maybe if you could give a concrete example or two of where this all would be advisable it would be easier to see why the facility would be desirable....?
On the other hand are you thinking of something like Basic where interaction with the interpreter is via a command line?
|
More the latter. I'm thinking in terms of languages that can be used as an interactive shell, as a scripting language with executable script files, and as compilable source.
In the REPL (read-eval-print-loop) model you can enter code on the fly. The problem is that sometimes I wish to change the code that I have entered. This implies there is an editing capability associated with my interactive shell. The issue, then, is what kind of editor do we want, and what is the relationship between the editor and the shell.
Thus there is the emacs model, in which the editor is boss, and you go into code execution mode from the editor. The trouble with this is it enslaves the interpreter to the editor. Maybe people don't like the chosen editor. Of course one could have an API so that the shell could be hooked up to any chosen editor, but I don't think much of that.
A general method is to write out buffers to a temp file, edit the temp file with an editor of choice, and read the temp file back into the interpreter. This sounds cumbersome but the cruft can all be automated.
One thought that has occurred to me, is to incorporate a primitive line editor, e.g., an ed clone, directly into the language. The idea is that the "editor" is, in effect, a preprocessor. Given that, one could have edit commands in source files. Whether this is a good idea is another matter.
USW. In short, I looking for ways to think about the problem and ways of thinking about it that I haven't thought of.
Richard Harter, cri@tiac.net LINK LINK Save the Earth now!! It's the only planet with chocolate. |
| |
| | | Richard Harter |  |
| Posted: Mon Aug 18, 2008 3:39 pm Post subject: Re: Edit commands in Command Line Interpreters |  |
On Fri, 15 Aug 2008 13:02:24 +0200, pjb@informatimago.com (Pascal J. Bourguignon) wrote:
| Quote: | cri@tiac.net (Richard Harter) writes:
|
[Snip interesting comments]
I hadn't quite thought of the issue in terms of persistence.
Richard Harter, cri@tiac.net LINK LINK Save the Earth now!! It's the only planet with chocolate. |
| |
| | | Pascal J. Bourguignon |  |
| Posted: Mon Aug 18, 2008 6:49 pm Post subject: Re: Edit commands in Command Line Interpreters |  |
| |  | |
cri@tiac.net (Richard Harter) writes:
| Quote: | In the REPL (read-eval-print-loop) model you can enter code on the fly. The problem is that sometimes I wish to change the code that I have entered. This implies there is an editing capability associated with my interactive shell. The issue, then, is what kind of editor do we want, and what is the relationship between the editor and the shell.
|
I fail to see the problem.
| Quote: | Thus there is the emacs model, in which the editor is boss, and you go into code execution mode from the editor. The trouble with this is it enslaves the interpreter to the editor.
|
I don't understand. Do you say slave because emacs is usually used to fork the lisp (or ruby or whatever) child process? This would be silly, we can use, for example, slime in emacs, to _connect_ to preexisting processes, in normal client/server fashion, there's no slave here.
| Quote: | Maybe people don't like the chosen editor. Of course one could have an API so that the shell could be hooked up to any chosen editor, but I don't think much of that.
|
Why not? It works very well, it's in the spirit of unix, and even of X (you could embed an editor X window inside any other application X window). If you don't like the editor, you can easily change it on the run:
C/USER[3]> (defun fact (x) (if (< x 0) 1 (* x (fact (1- x))))) FACT C/USER[4]> (ed 'fact) Waiting for Emacs... <-- Pff! I corrected the bug FACT <-- but I didn't liked the editor? FACT C/USER[5]> (fact 10) 3628800 C/USER[6]> (setf (ext:getenv "EDITOR") "/bin/ed") "/bin/ed" C/USER[7]> (ed 'fact) 54 <-- Yay! This time let's go for 1,$p <-- the STANDARD editor!  (DEFUN FACT (X) (IF (<= X 0) 1 (* X (FACT (1- X)))))
1,$s/X/N/g 1,$p (DEFUN FACT (N) (IF (<= N 0) 1 (* N (FACT (1- N)))))
wq 54 FACT FACT C/USER[8]> (fact 10) 3628800
| Quote: | A general method is to write out buffers to a temp file, edit the temp file with an editor of choice, and read the temp file back into the interpreter. This sounds cumbersome but the cruft can all be automated.
|
Yes, that is, it's not cumbersome at all it's already implemented every where in unix tools that require edition services from external editors. Notice that it is so standard that there are these EDITOR and VISUAl and other unix environment variables.
| Quote: | One thought that has occurred to me, is to incorporate a primitive line editor, e.g., an ed clone, directly into the language. The idea is that the "editor" is, in effect, a preprocessor. Given that, one could have edit commands in source files. Whether this is a good idea is another matter.
|
Of course it's a good idea, no need to fork off yet another process, and since you've got the source of the editor inside your image, you can correct any bug, or extend the editor easily. (In the case of emacs, it's actually not an editor, but a lisp virtual machine, and the editor grew over time by debugging and adding feature in lisp. (well, almost )
C/USER[9]> (com.informatimago.common-lisp.ed:ed 'fact) 1,$p (DEFUN FACT (N) (DECLARE (SYSTEM::IN-DEFUN FACT)) (BLOCK FACT (IF (<= N 0) 1 (* N (FACT (1- N)))))) w q C/USER[10]>
| Quote: | USW. In short, I looking for ways to think about the problem and ways of thinking about it that I haven't thought of.
|
I would say you need to understand better what an emacs is, and what a virtual machine is.
Try: The Craft of Text Editing LINK and of course, use and learn as much as you can of GNU emacs, and have a look at HEMLOCK and Climacs
And for virtual machines, learn some Smalltalk and give some time to Squeak (http://www.squeak.org but I'd try a squeak version 2-something perhaps, rather than the laters that are too much graphics oriented).
Also you could of course spend some time with some Common Lisp implementation, either standalone in a terminal (try clisp then, since it incorporates readline), or with emacs thru slime.
You could also try to use Movitz. It's a Common Lisp implementation on the bare metal, so you don't have an underlying unix virtual machine. You will have to use an embedded editor, or send your sources over the network to another virtual machine with emacs ;-)
The point is that you have (virtual) machines that have stored programs, where the programs are stored in the same memory as data, and therefore where programs ARE data, and therefore where you can modify the program as easily as any other data. When you have that, it doesn't matter if you split sub-virtual-machines, some specialised for editing some specialised for something else (that's what unix does, each process being its own specialised virtual machine. But thanks to the easily modifiable set of commands in a unix system persistent storage, when you're not happy with a program, you can easily modify and change it. (Unix is not a batch OS). In the same way, inside a REPL virtual machine, if you can write an embedded editor, so good, if you can use an external editor thru a red of sockets or pipes or underlying persistent storage mechanisms, so good too! Perhaps better even if this allows you to use a better editor.
-- __Pascal Bourguignon__ LINK
NEW GRAND UNIFIED THEORY DISCLAIMER: The manufacturer may technically be entitled to claim that this product is ten-dimensional. However, the consumer is reminded that this confers no legal rights above and beyond those applicable to three-dimensional objects, since the seven new dimensions are "rolled up" into such a small "area" that they cannot be detected. |
| |
| | | Reinder Verlinde |  |
| Posted: Mon Aug 18, 2008 8:09 pm Post subject: Re: Edit commands in Command Line Interpreters |  |
| |  | |
In article <d5095e94-f688-444f-8ca0-06cbe01e848a@l64g2000hse.googlegroups.com>, James Harris <james.harris.1@googlemail.com> wrote:
| Quote: | In the mental model I have, the reason source files exist is to allow functions to be coded.
|
There are options for allowing functions without having source files (examples: Forth, Lisp, Smalltalk)
| Quote: | if I use a common command-line interface I need to distinguish between commands which are to be executed immediately and commands which are being typed as part of creating another function. This is a bit like the old Basic interpreter scheme and one possibility is use of numbers to precede stored program lines.... Hmm. I'll list some options. See what you think. Can you see any mileage within any of these?
Option 1. Numbered lines * All stored lines are numbered * Numbers are NOT allowed targets for gotos * The numbers used are insignificant but are in order * First line of source for a given function is line number 1 * To replace a line type <N>r (where N is the line number) * To delete a line type <N>d * To enter new lines before an existing line type <N>b * To enter new lines after an existing line type <N>a * To exit line entry mode (which these last two invoke) do ...<something>...
|
'Numbered' is not a necessity. It could just be a special character, a limited set of 'start of line' commands, or an editor that knows the language grammar.
| Quote: | Option 2. Switch into editing mode * Type "edit <function name>" * To return to command mode type ...<something>...
Option 3. Multiple editing windows * Type "edit <function name>" to spawn an editor * CLI continues to run [...] And there is still the need to distinguish between commands and edits. Maybe some control key combination could be used???
|
That is option 4: use a special key combination for 'execute this'. This is what Apple's MPW Shell used. It had Return = insert a newline, Enter or option-Return = execute current selection/line as a command (Return and Enter (on the numeric keypad) are different keys on a Mac).
Reinder |
| |
| | | Richard Harter |  |
| Posted: Mon Aug 18, 2008 8:31 pm Post subject: Re: Edit commands in Command Line Interpreters |  |
| |  | |
On Mon, 18 Aug 2008 22:49:58 +0200, pjb@informatimago.com (Pascal J. Bourguignon) wrote:
| Quote: | cri@tiac.net (Richard Harter) writes: In the REPL (read-eval-print-loop) model you can enter code on the fly. The problem is that sometimes I wish to change the code that I have entered. This implies there is an editing capability associated with my interactive shell. The issue, then, is what kind of editor do we want, and what is the relationship between the editor and the shell.
I fail to see the problem.
|
Would your difficulty be that you've drunk too much kool-aid from that jug labeled emacs?
| Quote: |
Thus there is the emacs model, in which the editor is boss, and you go into code execution mode from the editor. The trouble with this is it enslaves the interpreter to the editor.
I don't understand. Do you say slave because emacs is usually used to fork the lisp (or ruby or whatever) child process? This would be silly, we can use, for example, slime in emacs, to _connect_ to preexisting processes, in normal client/server fashion, there's no slave here.
|
Enslaves is too strong a word; try subordinates.
| Quote: |
Maybe people don't like the chosen editor. Of course one could have an API so that the shell could be hooked up to any chosen editor, but I don't think much of that.
Why not? It works very well, it's in the spirit of unix, and even of X (you could embed an editor X window inside any other application X window). If you don't like the editor, you can easily change it on the run:
|
| Quote: | C/USER[3]> (defun fact (x) (if (< x 0) 1 (* x (fact (1- x))))) FACT C/USER[4]> (ed 'fact) Waiting for Emacs... <-- Pff! I corrected the bug FACT <-- but I didn't liked the editor? FACT C/USER[5]> (fact 10) 3628800 C/USER[6]> (setf (ext:getenv "EDITOR") "/bin/ed") "/bin/ed" C/USER[7]> (ed 'fact) 54 <-- Yay! This time let's go for 1,$p <-- the STANDARD editor!  (DEFUN FACT (X) (IF (<= X 0) 1 (* X (FACT (1- X)))))
1,$s/X/N/g 1,$p (DEFUN FACT (N) (IF (<= N 0) 1 (* N (FACT (1- N)))))
wq 54 FACT FACT C/USER[8]> (fact 10) 3628800
|
I like your example - geek to the core.
| Quote: |
A general method is to write out buffers to a temp file, edit the temp file with an editor of choice, and read the temp file back into the interpreter. This sounds cumbersome but the cruft can all be automated.
Yes, that is, it's not cumbersome at all it's already implemented every where in unix tools that require edition services from external editors. Notice that it is so standard that there are these EDITOR and VISUAl and other unix environment variables.
|
Unix is not the entirety of the world, you know, nor do all editors work in the UNIX way (TM).
| Quote: |
One thought that has occurred to me, is to incorporate a primitive line editor, e.g., an ed clone, directly into the language. The idea is that the "editor" is, in effect, a preprocessor. Given that, one could have edit commands in source files. Whether this is a good idea is another matter.
Of course it's a good idea, no need to fork off yet another process, and since you've got the source of the editor inside your image, you can correct any bug, or extend the editor easily. (In the case of emacs, it's actually not an editor, but a lisp virtual machine, and the editor grew over time by debugging and adding feature in lisp. (well, almost )
|
Oh, now I've got the source of the emacs editor in my interpreter, have I. My, my, what an utterly appalling idea.
The point is that one can put together a very simple line editor inside the interpreter. The question is whether that would be a good idea, not whether adding a powerhouse editor editor would be a good idea. Adding emacs an equivalent piece of cruft would, in my humble opinion, be a bad idea. YMMV.
| Quote: |
C/USER[9]> (com.informatimago.common-lisp.ed:ed 'fact) 1,$p (DEFUN FACT (N) (DECLARE (SYSTEM::IN-DEFUN FACT)) (BLOCK FACT (IF (<= N 0) 1 (* N (FACT (1- N)))))) w q C/USER[10]
USW. In short, I looking for ways to think about the problem and ways of thinking about it that I haven't thought of.
I would say you need to understand better what an emacs is, and what a virtual machine is.
|
You might very well say that. It seems to be the sort of thing that you say. Snort.
| Quote: | Try: The Craft of Text Editing LINK and of course, use and learn as much as you can of GNU emacs, and have a look at HEMLOCK and Climacs
|
Thanks for the reference.
| Quote: | And for virtual machines, learn some Smalltalk and give some time to Squeak (http://www.squeak.org but I'd try a squeak version 2-something perhaps, rather than the laters that are too much graphics oriented).
Also you could of course spend some time with some Common Lisp implementation, either standalone in a terminal (try clisp then, since it incorporates readline), or with emacs thru slime.
You could also try to use Movitz. It's a Common Lisp implementation on the bare metal, so you don't have an underlying unix virtual machine. You will have to use an embedded editor, or send your sources over the network to another virtual machine with emacs 
|
I do thank you for your suggestion.
| Quote: | The point is that you have (virtual) machines that have stored programs, where the programs are stored in the same memory as data, and therefore where programs ARE data, and therefore where you can modify the program as easily as any other data. When you have that, it doesn't matter if you split sub-virtual-machines, some specialised for editing some specialised for something else (that's what unix does, each process being its own specialised virtual machine. But thanks to the easily modifiable set of commands in a unix system persistent storage, when you're not happy with a program, you can easily modify and change it. (Unix is not a batch OS). In the same way, inside a REPL virtual machine, if you can write an embedded editor, so good, if you can use an external editor thru a red of sockets or pipes or underlying persistent storage mechanisms, so good too! Perhaps better even if this allows you to use a better editor.
|
I suspect that we have different notions about what constitutes a better editor.
Thank you for the comments about the virtues of virtual machines, such as they are. I am so delighted to learn that UNIX is not a batch OS. Fancy that, I always thought it was an MVS clone.
Richard Harter, cri@tiac.net LINK LINK Save the Earth now!! It's the only planet with chocolate. |
| |
| | | Pascal J. Bourguignon |  |
| Posted: Mon Aug 18, 2008 9:20 pm Post subject: Re: Edit commands in Command Line Interpreters |  |
| |  | |
James Harris <james.harris.1@googlemail.com> writes:
| Quote: | On 18 Aug, 16:55, c...@tiac.net (Richard Harter) wrote: On Fri, 15 Aug 2008 12:17:00 -0700 (PDT), James Harris
james.harri...@googlemail.com> wrote: On 15 Aug, 07:50, c...@tiac.net (Richard Harter) wrote: In most programming languages source code is in a file or files. The file(s) are either fed to a compiler or an interpreter; the user does not alter the source code during execution.
In some languages, e.g., command line interpreters and shell programs, the user can also enter code interactively. There are some extra features that useful for interactive mode. Thus:
(a) It is useful to be able to silently enter blocks of code, i.e., the interpreter does not execute the lines until an entire block has been entered.
(b) It is useful to be able to edit code on the fly, i.e., edit blocks of code as they are being entered (c) It is useful to be able to edit code that has already been entered and executed.
One way to do this is to run the interpreter within an editor, e.g., emacs. An alternative is to include editing commands directly within the language. Does anyone have opinions about or experience with the latter option?
I used to work with PL1022 which is basically a database access language. It was fairly standard for us to write code that would write and execute other PL1022 code. After a while this way of working became quite familiar and not as confusing as might be expected. However, IIRC, we had to work that way largely because the language did not readily permit us to do what we wished to do directly.
I thus tend to think that
a) generating code from within code is associated with poor languages, b) even if the user enters the code on the fly the whole process sounds prone to lead to confusion.
So I cannot comment on the options you mention. Maybe if you could give a concrete example or two of where this all would be advisable it would be easier to see why the facility would be desirable....?
On the other hand are you thinking of something like Basic where interaction with the interpreter is via a command line?
More the latter. I'm thinking in terms of languages that can be used as an interactive shell, as a scripting language with executable script files, and as compilable source.
In the REPL (read-eval-print-loop) model you can enter code on the fly. The problem is that sometimes I wish to change the code that I have entered. This implies there is an editing capability associated with my interactive shell. The issue, then, is what kind of editor do we want, and what is the relationship between the editor and the shell.
This sounds like something I have been thinking about as well. I don't have any complete answers. Maybe between us we can come up with some options.
In the mental model I have, the reason source files exist is to allow functions to be coded. Each function is like a command, there tends to be a one-to-one relationship between source file and function, and each new function becomes a new command. I could, therefore, ignore the existence of files and simply code different functions.
|
You just need to have the REPL environment keep the functions in an editable form. Old BASIC-like environment used to "compile" the source, actually encode the parse tree in some compact byte-coded format, and the LIST command would just unparse this tree to show the "source". You got "pretty-printing" for the same price.
Current REPL environment don't do that. They rely on the editor, or on readline and its history feature.
For example, I routinely enter and edit big, multiline commands or functions in bash, without going thru an editor. Just put set editmode=emacs in you ~/.bashrc, and use the history (C-p, C-n). But this is indeed similar to using an external editor. There is no way (AFAIK), knowing the name of a bash function, to recover the text of its source.
Similarly, most Common Lisp implementation just compile the code you give it at the REPL, and therefore cannot return the source (there's a standard function, CL:FUNCTION-LAMBDA-EXPRESSION, but it is allowed to return NIL instead of the source form of the function defined). However, as I already indicated, it's rather easy to add the bookkeeping needed in the REPL environment to store the source and retrieve it when you want to edit the function.
| Quote: | Like you, if I use a common command-line interface I need to distinguish between commands which are to be executed immediately and commands which are being typed as part of creating another function.
|
What's wrong with you people, don't you know emacs?
| Quote: | I'm not at all familiar with Emacs.
|
Ah ok. Well, you should.
| Quote: | FWIW I think that an editor should avoid switching between edit and command modes as they always annoy me.
|
Check. You'll love emacs, you'll hate vi.
| Quote: | I know not all terminals support things like the Alt key but the control key is fairly ubiquitous.
|
Actually, all terminals since the era of ASCII support the ESCape key, and this is what is transmited and what is expected by emacs for a Meta- key. So if your terminal or terminal emulator cannot map some Alt-X to ESC X, you can just type ESC X yourself.
| Quote: | How about all keys typed go straight into the document and Control key combinations perform functions or bring up menus. That way the user is always in edit mode. IIRC the Wordstar word processor worked something like that.
|
Yes. Guess where Wordstar took the idea from?
| Quote: | And there is still the need to distinguish between commands and edits. Maybe some control key combination could be used???
|
What command? What edit? Don't you realize it's always the SAME!
In emacs, there is a function that adds to number (+ 1 2), and there is a function that transpose two characters at the point (transpose-chars). There is no difference between these two functions. If you want to bind a key to a command that sums two numbers or a command that transpose the characters, to a key, you can do it equally well. With the same kind of function:
(local-set-key (kbd "<f5>") (lambda () (interactive) (transpose-chars))) (local-set-key (kbd "<f6>") (lambda () (interactive) (+ 1 2)))
and now when you type F5, the two characters at the point are transposed (exchanged), and when you type F5, the number 1 and 2 are added (and the result discarded, but it's up to you to send it someplace where it can be seen if you so desire).
Similarly, when you have the source of a function in some data structure, what difference can you make between an expression that will modify that data structure and another that would modify another data structure? It's exactly the same! And notice how there is absolutely no difference between code and data: of course code can be sent to the evaluator to be "executed", but the data can also be sent to the evaluator to be "executed" (as long as you provide the "language" to interpret that data):
C/USER[1]> (defparameter *funs* (make-hash-table)) *FUNS* C/USER[2]> (setf (gethash 'fact *funs*) '(defun fact (x) (if (< x 0) 1 (* x (fact x))))) (DEFUN FACT (X) (IF (< X 0) 1 (* X (FACT X)))) C/USER[3]> (eval (gethash 'fact *funs*)) FACT C/USER[4]> (setf (gethash 'fact *funs*) (subst '<= '< (gethash 'fact *funs*))) (DEFUN FACT (X) (IF (<= X 0) 1 (* X (FACT X)))) C/USER[5]> (setf (gethash 'fact *funs*) (subst '(fact (1- x)) '(fact x) (gethash 'fact *funs*) :test (function equal))) (DEFUN FACT (X) (IF (<= X 0) 1 (* X (FACT (1- X))))) C/USER[6]> (eval (gethash 'fact *funs*)) FACT C/USER[7]> (fact 10) 3628800 C/USER[8]> (defparameter *pers* (make-hash-table)) *PERS* C/USER[9]> (setf (gethash 'john *pers*) '(john (mother mary) (father job) (age 10))) (JOHN (MOTHER MARY) (FATHER JOB) (AGE 10)) C/USER[10]> (setf (gethash 'john *pers*) (subst '(age 12) '(age 10) (gethash 'john *pers*) :test (function equal))) (JOHN (MOTHER MARY) (FATHER JOB) (AGE 12)) C/USER[11]> (push 'person (gethash 'john *pers*)) (PERSON JOHN (MOTHER MARY) (FATHER JOB) (AGE 12)) C/USER[12]> (defmacro person (name &rest attributes) `(make-alive :name ',name :attributes ',attributes)) PERSON C/USER[13]> (defun make-alive (&key name attributes) (print `(,name is alive))) MAKE-ALIVE C/USER[14]> (eval (gethash 'john *pers*))
(JOHN IS ALIVE) (JOHN IS ALIVE) C/USER[15]>
All this is trivial and has been known for more than 50 years now... -- __Pascal Bourguignon__ LINK
ATTENTION: Despite any other listing of product contents found herein, the consumer is advised that, in actuality, this product consists of 99.9999999999% empty space. |
| |
| | | James Harris |  |
| Posted: Mon Aug 18, 2008 9:26 pm Post subject: Re: Edit commands in Command Line Interpreters |  |
| |  | |
On 18 Aug, 16:55, c...@tiac.net (Richard Harter) wrote:
| Quote: | On Fri, 15 Aug 2008 12:17:00 -0700 (PDT), James Harris
james.harri...@googlemail.com> wrote: On 15 Aug, 07:50, c...@tiac.net (Richard Harter) wrote: In most programming languages source code is in a file or files. The file(s) are either fed to a compiler or an interpreter; the user does not alter the source code during execution.
In some languages, e.g., command line interpreters and shell programs, the user can also enter code interactively. There are some extra features that useful for interactive mode. Thus:
(a) It is useful to be able to silently enter blocks of code, i.e., the interpreter does not execute the lines until an entire block has been entered.
(b) It is useful to be able to edit code on the fly, i.e., edit blocks of code as they are being entered (c) It is useful to be able to edit code that has already been entered and executed.
One way to do this is to run the interpreter within an editor, e.g., emacs. An alternative is to include editing commands directly within the language. Does anyone have opinions about or experience with the latter option?
I used to work with PL1022 which is basically a database access language. It was fairly standard for us to write code that would write and execute other PL1022 code. After a while this way of working became quite familiar and not as confusing as might be expected. However, IIRC, we had to work that way largely because the language did not readily permit us to do what we wished to do directly.
I thus tend to think that
a) generating code from within code is associated with poor languages, b) even if the user enters the code on the fly the whole process sounds prone to lead to confusion.
So I cannot comment on the options you mention. Maybe if you could give a concrete example or two of where this all would be advisable it would be easier to see why the facility would be desirable....?
On the other hand are you thinking of something like Basic where interaction with the interpreter is via a command line?
More the latter. I'm thinking in terms of languages that can be used as an interactive shell, as a scripting language with executable script files, and as compilable source.
In the REPL (read-eval-print-loop) model you can enter code on the fly. The problem is that sometimes I wish to change the code that I have entered. This implies there is an editing capability associated with my interactive shell. The issue, then, is what kind of editor do we want, and what is the relationship between the editor and the shell.
|
This sounds like something I have been thinking about as well. I don't have any complete answers. Maybe between us we can come up with some options.
In the mental model I have, the reason source files exist is to allow functions to be coded. Each function is like a command, there tends to be a one-to-one relationship between source file and function, and each new function becomes a new command. I could, therefore, ignore the existence of files and simply code different functions.
Going back to your post, the same functions can be called from the shell as from other functions. For example, function X could be invoked as
X parm1 parm2
or
X.(parm, parm2)
where the first is command format and the second is function invocation format. Like you, if I use a common command-line interface I need to distinguish between commands which are to be executed immediately and commands which are being typed as part of creating another function. This is a bit like the old Basic interpreter scheme and one possibility is use of numbers to precede stored program lines.... Hmm. I'll list some options. See what you think. Can you see any mileage within any of these?
Option 1. Numbered lines * All stored lines are numbered * Numbers are NOT allowed targets for gotos * The numbers used are insignificant but are in order * First line of source for a given function is line number 1 * To replace a line type <N>r (where N is the line number) * To delete a line type <N>d * To enter new lines before an existing line type <N>b * To enter new lines after an existing line type <N>a * To exit line entry mode (which these last two invoke) do ...<something>...
Option 2. Switch into editing mode * Type "edit <function name>" * To return to command mode type ...<something>...
Option 3. Multiple editing windows * Type "edit <function name>" to spawn an editor * CLI continues to run
This one is rather similar to existing windowed environments if an existing editor is used - e.g. Notepad on Windows and vi on Unix, say. As a difference we could say that changes made in the editor are immediately current without being saved, if that helps.
The above suggests that to invoke a function X, rather than typing "run" as with Basic the user needs to type "X" along with any parameters.
Maybe the CLI could compile functions on the fly as needed.
I guess you are thinking of allowing the user to write blocks of code at the command prompt so
for a in 1 .. 10 <do something> <do something else> end for
The problem being what to do if the user wants to edit the block before completing it. Not sure. How about
Option A. Prohibit use of blocks at the CLI Option B. Give each new CLI block a default name
Just some thoughts.
| Quote: | Thus there is the emacs model, in which the editor is boss, and you go into code execution mode from the editor. The trouble with this is it enslaves the interpreter to the editor. Maybe people don't like the chosen editor. Of course one could have an API so that the shell could be hooked up to any chosen editor, but I don't think much of that.
|
I'm not at all familiar with Emacs. FWIW I think that an editor should avoid switching between edit and command modes as they always annoy me. I know not all terminals support things like the Alt key but the control key is fairly ubiquitous. How about all keys typed go straight into the document and Control key combinations perform functions or bring up menus. That way the user is always in edit mode. IIRC the Wordstar word processor worked something like that.
| Quote: | A general method is to write out buffers to a temp file, edit the temp file with an editor of choice, and read the temp file back into the interpreter. This sounds cumbersome but the cruft can all be automated.
One thought that has occurred to me, is to incorporate a primitive line editor, e.g., an ed clone, directly into the language. The idea is that the "editor" is, in effect, a preprocessor. Given that, one could have edit commands in source files. Whether this is a good idea is another matter.
|
And there is still the need to distinguish between commands and edits. Maybe some control key combination could be used???
| Quote: | USW. In short, I looking for ways to think about the problem and ways of thinking about it that I haven't thought of.
|
Me too. Any thoughts on the above?
-- James |
| |
| Page 1 of 2 .:. Goto page 1, 2 Next | |
|
|