JavaScript, TCL, Scheme, Python, REXX
What
Why
Approaches
Customization dialogs (ui characteristics, toolbar content, etc.)
Macros
Script languages
Plugins
Progression
Relation to framework
Effect on system design
Expose “low level”
Multiple scriptable languages
“End users are not programmers.”
Javascript to Java + HTML
www.python.org
JACL www.scriptics.com -> TCL
FESI (=Javascript) / ECMAScript http://home.worldcom.ch/~jmlugrin/fesi
End-User Programming
For some applications, users need to be able to modify how the application works. This happens because an application must accommodate many different uses, but the user has a particular situation.
This can come on many levels. In the simplest form, we wouldn’t even call it programming. For example, consider setting up preferences for an application. The user is usually guided through some dialogs with lots of checkboxes and lists, and can determine many aspects of the application’s behavior. We won’t explore this form any further.
An intermediate form involves dealing with repetitive tasks. For example, suppose I’m writing a reference manual, and I want all method definitions to be 14-point bold Helvetica, and all arguments to be shown in italics. (Next week I might change my mind.) Many word processors have the notion of user-created styles, and would let you define new styles “Method definition” and “argument,”, and perhaps assign a single keystroke to apply that style. As another example, in using an OCR and imaging program you might want to apply a certain set of image parameters to each page.
An advanced form of programming might let the user develop scripts that are almost full programs. For example, HTML files with Javascript allow a web author to program activities on a web page. Spreadsheets often let users define their own functions.
Plugins allow for even more advanced programming. (We’ve talked about them already.) While users “could” develop the plugins, often they buy them instead.
Finally, some systems are so open, and used by such skilled users, that it can be hard to distinguish the end user from the developer. The Emacs editor and the Linux operating system both have this flavor.
Once you reach that level, you’re starting to look at developers rather than typical end users, and it brings us full circle back to frameworks.
We’ll discuss the implications of end-user programming on the user interface, approaches and system implications of supporting repetitive tasks, and approaches and implications of scripting languages.
Programming and the User Interface
Progressive disclosure
Exposed model
Users are not programmers.
Dynamically typed language, simple syntax.
Don’t be a programming language designer.
Implications of Programming for the User Interface
[KEY] The typical user should be able to use the system with no customization or programming. (If not, you haven’t done enough for them.)
“Policy-free” can be a tempting approach. “What color are links? Let the user choose. Does clicking bring the window to the front? Let the user choose. Should the tool fetch email, or wash windows? Let the user choose.”
Users don’t know which way is better. It may be our job to put on a usability testing hat, and find out for them. Remember also that when you allow customization, people will customize differently, yielding different operating environments. This makes training and support more difficult.
Customization can be useful, but be sure to balance its costs against its benefits.
[KEY] “Progressive Disclosure”: If you allow customization or programming, don’t require the user to learn about those features until they’re ready for them.
Apple’s HyperCard used this approach. HyperCard had several levels of access. At the simplest level, it allowed read-only hypertext. At higher levels, it allowed access to the authoring language.
Supporting Repetitive Tasks
Users sometimes have to repeat a series of steps many times. This may be for one session only, or as part of their everyday use of the program.
This is often thought of as a macro facility, or in more user-oriented terms, a record-and-play system. (It is sometimes even modeled as a small picture of a tape recorder.)
It works like this: the user is using the program, and decides to record actions. They do some action to start recording (usually a menu item or special button). Usually a special indicator will light up to show “recording in progress.” The user does the actions they normally would, and they have their usual effect. When the user is finished, they turn off recording mode. They may be prompted to identify a name and keystroke for their actions, or there may be just a single active recording at a time. The user has just “programmed” a new function. From that point, the user can activate the recorded macro, and the stored actions will be re-executed.
How do we implement this behavior? One of the best ways is through the Command pattern. It treats each user action as an object, and has a method execute() to make it happen. When recording mode is on, you can not only execute the command, but store it in the recorder as well. (Think of the recorder as a composite command.) When it’s time to execute the macro, it can be done by re-playing each of the stored commands.
You have to address a number of issues to fully implement this scheme. What happens if a command fails – does the macro abort or undo? Can you execute a macro within a macro? Can you store multiple macros? Can the user edit a macro? Can the macro be set up to request input while it’s playing back? (For example, we might have a macro to select all text in a line containing a search string, but we want to prompt for the search string each time the macro runs.)
The Command pattern is also an excellent way to implement “undo” support. Once present for “undo,” adding a macro/recording facility is not a lot of work. It can ease the user’s burden substantially.
Scripting languages
Some applications need to provide more programmability to their users. This can happen because the program is esoteric with skilled users, or because the program is at an infrastructure layer, with little personality of its own.
The best known example is the Emacs editor. Emacs has core editing functionality at its base, but everything above it is implemented in Lisp.
Scripting languages are usually interpreted. They tend to have a simple syntax. While they may have looping and test instructions, they often provide access to high-level functions (e.g., sophisticated string handling or pattern matching). They usually don’t require the user to take care of things like memory management; they don’t tend to have pointers; they often have high-level data structures. Some of the best-known examples include Javascript, Perl, Python, REXX, Scheme (Lisp), and TCL. And of course, many projects have developed their own scripting languages.
Which scripting language should you use?
Your own scripting language
Should you just invent your own scripting language?
* Completely under your control
* Tuned to use of your system
* You can start small and grow it as you need to.
There is a simple rule to help you make this decision:
[Never design your own language.]
Never?! Yes – the successes from breaking this rule are far outnumbered by the failures caused by following it.
Why? Because it draws you away from your main job. Suppose through herculean, expert effort your team expends a year or so of work, and manages to produce a new, full-featured language, just as good as those with many times that effort. What must you do next? Someone must document the language. If it’s full-featured, this documentation will probably be a book in itself. Who can use it? Practically nobody – maybe you need a tutorial book and a class too. Then you have to build the momentum from people learning your language and learning all the little tricks that stretch its use. The users may pressure you into developing debugging and other tools, forcing you to expend even more effort.
That’s the best case. Consider a worse (and perhaps more typical) case. The programmer decides he’d like to develop a language (and what programmer wouldn’t?). They get started, but for the first release, they only support the simplest constructs. (They’re not compiler developers, so it was harder than they thought it would be.) Another developer takes over for the next release and tries to add more features. They’re not compiler writers either, so they end up putting in weird constraints. (“You can use recursion, but never call a routine more than 20 times in a single recursion”; “Don’t use more than 100 strings in a program”; etc.) The language is smaller than in the “best case” above (there was no time to do more), but all the restrictions make it harder to document. Customers still need training, but now they fight bugs and limitations.
Compare the situation to the team that uses an existing language. They have to buy (or find) and integrate an implementation, but that’s a lot less work than starting from scratch. They may find that some work they were planning to implement “in the back” can be done more easily in the scripting language, thus opening up the system. When they get ready to document it, they really only have to document how to interface to their system — the language is already defined. There are language manuals, tutorials, newsgroups full of helpful people — a community that makes the language a platform. And using that language can be a selling point to its community.
Is it ever appropriate to develop your own scripting language? It could be. In some circumstances, it’s probably the right thing to do: spreadsheet, special-purpose multimedia, etc. where the typical scripting language “model” just doesn’t fit the application’s model. Don’t take this step lightly though – it definitely adds risk to your project.
[Shoot for 5-10x increase in power.]
Choosing a scripting language
You have to choose a scripting language, just as you have to choose a programming language. You must balance the popularity of the language, how well it fits your application, availability of programmers, how well potential users know it, cost, learning time, etc.
One important consideration is the availability of an implementation. We’ll look at several candidate languages with a quick evaluation.
ECMAscript/Javascript/JScript
ECMAscript is a language included in the Netscape and Microsoft web browsers. From the name, Javascript sounds like a variant of Java, but it’s really a different language. ECMAscript is the standardized version of the language (not yet fully supported by most browsers).
[Sample code]
There’s a Java implementation available called FESI (“fuzzy”), located at http://home.worldcom.ch/~jmlugrin/fesi/index.html.
Lisp/Scheme
Lisp is an old language (older than anything in common use except FORTRAN and possibly COBOL). Its forte is list handling. Scheme is one of Lisp’s more popular variants.
[sample]
Two implementations available are Kawa (cygnus.org) and JScheme (Brandeis U.).
Python
Python is an interpreted, object-oriented language, with high-level data structures, pattern matching, and dynamic typing. (Guido van Rossum)
[sample]
The Python home page is at http://www.python.org. There is a Java version known as JPython.
REXX
REXX is a scripting language available on almost all IBM machines. It now has a “net” version known as netREXX.
[sample]
The netREXX implementation is available at ibm.com.
TCL
TCL is a scripting language developed by John Osterhout. It has similar capabilities to PERL, but with more straightforward syntax.
[sample]
TCL is being developed by Scriptics, at http://www.scriptics.com. They have an implementation known as JACL.
Etc.
There are other languages out there: PERL, various Unix shells, Basic, etc., etc. Remember that for all-Java programs, you need to find a suitable Java implementation. (If your system is not all-Java, you may be able to use a language implemented in C, C++, etc.)