A good command line interface allows its users to pack a lot of useful work into strings the size of twitter messages. There is no room for boiler-plate, no patience even for parentheses. Identifiers must be short. Parameters must have good defaults. Failure should usually be obvious and safe, allowing users to refine their commands and try again.
A common property of most command-line interfaces today: they are of an imperative, procedural nature. It is difficult to declare the answer before prompted, which ties the model to time. The querying app must often wait for a prompt to be answered – i.e. interactive rather than reactive. It is difficult to modify an answer to an earlier query (e.g. “What is your name?”). Queries on the system are volatile and must be polled to remain up-to-date. System behavior is sensitive to order of expression. A command expressed twice will typically result in two distinct behavior instances.
A declarative, reactive command line would have the following properties:
- Behavior of system is declarative. That is, users declare how a system behaves with a fair level of idempotence (declaring a behavior twice doesn’t result in twice the behavior) and commutativity (order of declaration not so critical).
- Behavior of system is reactive. Any earlier declaration of behavior may be revoked or modified.
- Time is generally implicit, to keep lines short. It is possible to declare many behaviors as occurring at the same time, i.e. a batch update.
- Relationship between user and application may be maintained through command line. Users may anticipate answers to prompts, and declare answers in advance. Users may change declared answer at any time.
- Prompts to user are inherently reactive, not interactive, meaning the app does not implicitly wait. If app must wait for valid answer, this must be modeled explicitly in the app – if(bad_answer) then nothing else doCoolStuff.
- Most output to user is also reactive and subject to change over time. I.e. “Hello, World!” might later change to “Hello, Console!”. This could be expressed quite naturally with graphical output or curses. If streaming, a less natural mechanism might be required – but it could at least be symmetric to how the user modifies declarations.
I envision such a system working a lot like a tuple space: CLI actions add or remove declarations from the space. A simple case might be declaration like `+lights` turning on the house lights, and `-lights` turning them back off. At least one service (the shell) is observing the space and searching for other services to fulfill each request, but I think it might be more interesting to run this in reverse: allow any number of observers to `interpret` the declarations when deciding their behavior, and attach the console to different tuple spaces as needed.
Prompts from the application are given a unique structural identity, e.g. of the form “com.example.hello.user_name”, and all prompts on the ID will return the same value, which can be changed over time. Prompts can carry a lot of extra meta-data, including query strings.
Properties such as filters, queries, histories, suggestions and tab-completion, macros, aliases, topics or switching, CSCW, and persistence would help modernize the shell. Structured text data rather than plain strings could improve filters and queries a great deal, and support level of detail. JSON may be a bit too verbose, but something like ML9 would allow adding just a little structure where necessary and implicitly annotating each declaration with metadata.