We dissect nature along lines laid down by our native language...Language is not simply a reporting device for experience but a defining framework for it.Unix supports a wider variety of application languages than any other single operating system; indeed, it probably hosts more different languages than every other operating system in the history of computing combined.-- Benjamin Lee Whorf
There are at least two excellent reasons for this huge diversity. One is the wide use of Unix as a research and teaching platform. The other (far more relevant for working programmers) is the fact that matching your application design with the proper implementation language(s) can make an immense difference in your productivity. Therefore the Unix tradition encourages the design of special-purpose languages, minilanguages, and what we will call scripting languages -- those designed specifically to glue together other applications and tools.
To apply the Unix philosophy effectively, you'll need to have more than just C in your toolkit. You'll need to learn how to use some of Unix's other languages (especially scripting languages), and how to be comfortable mixing multiple languages in specialist roles within large programming systems.
In this chapter we'll survey C and its most important alternatives, discussing their strengths and weaknesses and the sorts of tasks to which they are best matched. The languages covered will be C, C++, shell, Perl, Tcl, Python, Java, and Emacs Lisp. Each survey section will include case studies on applications written using these languages, and references to other examples and tutorial material. High-quality implementations of all these languages are available in open source on the Internet.
Warning: choice of application language is one of the archetypal religious issues in the Internet/Unix world. People get very attached to these tools and will sometimes defend them past all reason. If we achieve our aim zealots of all stripes may be offended by this chapter, but everyone else will learn from it.
It may therefore seem perverse to assert that in C and C++ are nowadays almost always the wrong vehicle for beginning new applications development. But it's true; C and C++ optimize for machine efficiency at the expense of increased implementation and (especially) debugging time. While it still makes sense to write system programs and time-critical kernels of applications in C/C++, most other sorts of implementation (including application prototyping) are better served by the newer generation of interpreted and scripting languages.
The central problem of C and C++ is that they require programmers to do their own memory management (to declare variables, explicitly manage pointer-chained lists, dimension buffers and detect or prevent buffer overruns, to allocate and deallocate dynamic storage).
This is an enormous source of complication and error. In fact, it is generally estimated that 90% or more of the errors made by experienced C programmers are memory-management faults. Buffer overruns are a common cause of crashes and security holes. Dynamic-memory management is particularly notorious for spawning insidious and hard-to-track bugs (such as memory leaks).
[FIXME: can we support these folkloric observation with actual studies?]
Not so long ago, manual memory management made sense anyway. Clock cycles and core were expensive, and conserving both was a vital part of a programmer's job. It seemed worth accepting the huge debugging overhead and even a higher rate of errors in delivered product to make programs that would actually fit on small systems.
But there are no ``small systems'' any more, not in mainstream applications programming. Under today's conditions, an implementation language that automates away memory management (and buys an order of magnitude decrease in bugs at the expense of using a bit more more cycles and core) makes a lot more sense.
The Unix world has been slowly coming around to this point of view in practice, especially since 1990 or so; this is shown by the increasing popularity of Perl and other scripting languages. But the evolution of practice has not yet (as of mid-2000) led to a wholesale change in conscious attitudes; as this book is written, many Unix programmers have not yet fully absorbed the lesson Perl and Python have been teaching. We may expect this to change in the next few years.
(We can see the same trend outside the Unix world, for example in the continuing shift from C++ to Visual Basic evident in applications development under Microsoft Windows and NT.)
The arguments against C and C++ apply with equal force to other conventional compiled languages such as Pascal, Ada, Algol, PL/I, Fortran, and compiled Basic dialects. Despite occasional heroic efforts such as the Eiffel/Sather family, the differences between conventional languages remain superficial when set against their basic design decision to leave memory management to the programmer. None is clearly superior to C/C++, and none are in significant use in the Unix or Windows worlds. Accordingly we will not survey them here.
This is not actually a new idea in the Unix world. As far back as the mid-1970s, in an era of far smaller machines, the Unix shell (the interpreter for commands typed to a Unix console) was designed as a full interpreted programming language. It was common even then to write programs entirely in shell, or to use the shell to write glue logic that knit together canned utilities and custom programs in C into wholes greater than the sum of their parts. Classical introductions to the Unix environment (such as [UPE] cited in the preface) have dwelt heavily on this tactic, and with good reason; it was one of Unix's most important innovations.
Advanced shell programming mixes languages freely, employing both binaries and interpreted elements from half a dozen or more other languages for subtasks. Each language does what it does best, and the global complexity of the whole is much lower than it would be had it been coded as one big lump in a general-purpose languages.
This is a knowledge-intensive (rather than coding-intensive) style of programming. To make it work, you have to have both working knowledge of a suitable variety of languages and expertise about what they're best at and how to fit them together. In our survey, we will try to point you at references to help you with the first and an overview to convey the second. For each language surveyed we will include case studies of successful programs that exemplify its strengths.
Programs that must be portable across multiple operating systems may also be good candidates for C (indeed this is the purpose for which it was originally designed). Some of the alternatives to C that we shall discuss below are, however, increasingly penetrating major non-Unix operating systems; in the near future, portability may be less a distinguishing advantage of C.
Sometimes the leverage to be gained from programs like parser generators or GUI builders that generate C code is so great that it justifies C coding of the rest of a small application.
And, of course, C proved indispensible to the developers of all its alternatives. Dig down through enough implementation layers under any of the other languages surveyed here and you will find a core implemented in pure, portable C.
The best reference and tutorial on C is still [K&R].
High-quality C compilers are available as open-source software over the Internet; the best-known and most widely used is the Free Software Foundation's GNU C Compiler (GCC), which has become the native C of all open-source Unix systems and many even in the closed-source world. GCC sources are available at the FSF's FTP site, ftp://prep.ai.mit.edu/pub/gnu.
GCC ports are available for Microsoft's family of operating systems. Differing OS bindings can of course cause C portability problems, but Windows NT at least theoretically supports an ANSI/POSIX-compliant C API.
Fetchmail is a network gateway program. Its main purpose is to translate between POP3 or IMAP remote-mail protocols and the Internet's native SMTP protocol for email exchange. It is in extremely widespread use on Unix machines that use intermittent SLIP or PPP connections to Internet service providers, and as such probably touches a sizeable fraction of the Internet's mail traffic.
The program does only the simplest kind of dynamic-memory management; its only complex data structures are a singly-linked list of per-mailserver control blocks built just once, at startup time, and changed only in fairly trivial ways afterwards. This substantially erodes the case against using C by sidestepping C's greatest weakness.
On the other hand, these control blocks are fairly complex (including all of string, flag, and numeric data) and would be difficult to handle as coherent fast-access objects in an implementation language without an equivalent of the C struct feature. Most of the alternatives to C are weaker than C in this respect.
Finally, fetchmail requires the ability to parse a fairly complex specification syntax for per-mailserver control information. In the Unix world this sort of thing is classically handled by using C code generators that grind out source code for a tokenizer and grammer parser from declarative specifications. This also argued for using C.
Fetchmail might reasonably have been coded in Python, albeit with possibly significant loss of performance. Its size and data-structure complexity would have excluded shell and Tcl right off and strongly counterindicated Perl, and the application domain is outside the natural scope of Emacs Lisp. A Java implementation wouldn't have been an unreasonable path, but Java's object-oriented style and garbage collection would have offered little leverage on fetchmail's specific problems over what C already yields. Nor could C++ have done much to simplify the relatively simple internal logic of fetchmail.
However, the real reason fetchmail is a C program is that it evolved by gradual mutation from an ancestor already written in C.
Notably, however, fetchmail's interactive configurator is written in Python. We'll discuss that case along with that language.
This has not happened. Part of the fault can be laid to problems in C++ itself; the requirement that it be backward-compatible with C forced a great many compromises on the design and made the language overall rather baroque and excessively complicated. That requirement also prevented C++ from going to fully automatic dynamic-memory management and addressing C's most serious problem.
Part of the fault must be laid to the failure of OO itself to live up to expectations. The OO design concept initially proved valuable in the design of graphics systems, graphical user interfaces, and certain kinds of simulation. To the surprise and gradual disillusionment of many, it has proved hard to demonstrate significant benefits of OO outside those areas. A decade later, inspection of open-source archives (in which choice of language reflects developers' judgements rather than corporate mandates) reveals that C++ is still very little used outside of GUI and multimedia toolkits.
When all is said and done, C++ is basically just another conventional language. It confines the memory-management problem somewhat better than C does, but doesn't solve it. For many types of application its OO features are not significant, and simply add complexity to C without yielding much leverage. The world is not short of free C++ compilers; if C++ were unequivocally superior to C it would now dominate.
Consider using C++ if an existing C++ toolkit or service library offers powerful leverage for your application, or if you're in one of the application areas mentioned above for which an OO language is known to be a large win.
The classic C++ reference is Stroustrup's The C++ Programming Language (Second Edition) [BS]. You will find an excellent tutorial on C++ and OO methods in [SH].
GNU C (referenced above) can be run in a mode that compiles C++. The language is therefore universally available on Unix and on Microsoft operating systems; comments made under C above also apply here. At least one free C++ class library (wxWindows, available at URL http://web.ukonline.co.uk/julian.smart/wxwin, or via title search for "wxWin") offers cross-platform GUI building with native look-and-feel on each platform.
The Qt toolkit is a critical and visible component of the KDE project, the senior of the open-source world's two efforts to produce a competitive GUI and integrated set of desktop productivity tools.
Qt's C++ implementation exhibits the strengths of an OO language for encapsulating user-interface components. In language supporting objects, a visual hierarchy of interface widgets can be cleanly expressed in the code by a hierarchy of class instances. While the sort of thing can be simulated in C with explicit indirection through hand-rolled method tables, such code is much cleaner in C++.
The Qt source code and reference documentation is available at http://www.trolltech.com/.
Simple shell programs are extremely easy and natural to write. As program size gets larger, however, they tend to become rather ad hoc. Some parts of shell syntax (notably its quoting and statement-syntax rules) can be very confusing. These drawbacks generally relate to compromises in the programming-language part of the shell's design made to preserve its utility as an interactive command-line interpreter.
Programs are often described as being ``in shell'' even when they are not pure shell but include heavy use of C filters like sort(1) and of standard text-processing mini-languages like sed(1) or awk(1). This sort of programming has been in decline for some years, however; nowadays such elaborate glue logic is generally written in Perl, with shell being reserved for the simplest kinds of wrappers (for which Perl would be overkill) and system boot-time initialization scripts (which cannot assume Perl is available).
Such basic shell programming should be adequately covered in any introductory Unix book. The Kernighan & Pike book [UPE] cited in the Preface's bibliography remains one of the best sources on intermediate and advanced shell programming. Korn shell implementations or clones are present on every Unix.
While Bourne and Korn-shell clones have been sporadically available on non-Unix operating systems, shell programs are not (practically speaking) at all portable off Unix.
Perl's strongest point is its extremely powerful built-in facilities for pattern-directed processing of textual, line-oriented data formats; it is unsurpassed at this. It also includes far stronger data structures than shell, including dynamic arrays of mixed element types and a ``hash'' or ``dictionary'' type that supports convenient and fast lookup of name-value pairs. Finally, it includes a rather complete and well thought out internal binding of virtually the entire Unix API, drastically reducing the need for C and making it suitable for jobs like simple TCP/IP clients and even servers. Another strong advantage of Perl is that a large and dedicated open-source community has grown up around it. Its home on the net is at URL http://www.perl.com. Dedicated Perl hackers have written hundreds of freely reusable Perl modules for many different programming tasks. These include everything from structure-walking of directory trees through X toolkits for GUI building, through excellent canned facilities for supporting HTTP robots and CGI programming.
. Perl's main drawback is that parts of it are irredeemably ugly, complicated, and must be used with caution and in stereotyped ways lest they bite (its argument-passing conventions for functions are a good example of all three). It is harder to get started in Perl than it is in shell. Though small programs in Perl can be extremely powerful, it requires careful discipline to maintain modularity and keep a design under control as program size increases. Because some limiting design decisions early in Perl's history could not be reversed, many of the more advanced features have a fragile, jerry-rigged feel about them.
The definitive reference on Perl is Programming Perl [PP]. This book has nearly everything you will ever need to know in it, but is notoriously badly organized; you will have to dig to find what you want. A more introductory and narrative treatment is available in Learning Perl [LP].
Perl is universal on Unix systems. Perl implementations are available (and even well documented) for the Microsoft family of operating systems and on the Macintosh as well. PerlTk provides cross-platform GUI capability.
Imgsizer is a nearly ideal example of the sort of small, pattern-driven text-processing tool at which Perl excels. Observe the use of httpget(1) and the ImageMagick identify(1) as specialist tools for fetching Web documents and extracting the pixel sizes of images.
The httpget(1) invocation could actually have been eliminated with the use of an HTTP client class downloaded from CPAN. But that client class is not guaranteed available in a stock Perl (illustrating one of the language's problems for small scripts distributed standalone like this one). The httpget(1) code, itself written in Perl, addresses this problem by inlining a copy of the relevant libraries; it is ubiquitous on the Linux and FreeBSD systems fior which this script was targeted.
The dynamic string-handling and sophisticated regular-expression matching required would have made imgsizer quite painful to write in C or C++; that version would also have been much larger and harder to read. Java would have solved the implicit memory-management problem, but is hardly more expressive than C/C++ at text pattern matching.
Tcl and Python are both good for small scripts of this type, but both lack the Perl convenience features for regular-expression matching that this script uses heavily; an implementation in either would have been reasonable, but much less compact and expressive. An Emacs Lisp implementation would have been even faster to write and more compact than the Perl one, but probably painfully slow to use due to Emacs's size and long start-up time.
Keeper is a good example of a medium-to-large interactive Perl application. The command-line interface is line-oriented and patterned after a specialized shell or directory editor; note the embedded help facilities. The working parts make very heavy use of file and directory handling, pattern matching, and pattern-directed editing. Note the ease with which keeper generates Web pages and electronic-mail notifications from programmatic templates. Note also the use of a canned Perl module to automate walking various functions over directory trees.
At about 3300 lines, this application is probably pushing the size and complexity limit of what one should attempt in a single Perl program. Nevertheless, most of it was written in a period of six days. In C, C++ or Java it would have taken a minimum of six weeks and been extremely difficult to debug or modify after the fact. It is way too large for Tcl. A Python version would probably be structurally cleaner, more readable, and more maintainable -- but also more verbose (especially near the pattern-matching parts). An Emacs mode could readily do the job, but Emacs is not well suited for use over a telnet link that is often slowed to a crawl by server congestion.
The main advantage of Tcl itself is that it is extremely flexible and radically simple. The syntax is very odd but totally consistent. There are no reserved words, and is no syntactic distinction between a function call and ``built-in'' syntax; thus the Tcl language interpreter itself can be effectively redefined from within Tcl (which is what makes projects like Expect reasonable).
The main drawback of Tcl is that it has only weak facilities for namespace control and modularity, and one of those (upvar) is rather dangerous if not used with great caution. It scales up very poorly -- it is hard to organize and debug Tcl programs of even moderate size (more than a few hundred lines) without tripping over your own feet. The oddities of the syntax can be a problem as well; the distinction between string quotes and braces will probably give you headaches for a while, and the rules for when things need to be quoted or braced are a bit tricky.
TCL also cannot handle I/O to binary files at all, and only provides access to a relatively small commonly-used part of the Unix API (essentially just file handling, process-spawning, and sockets). Indeed, Tcl has the flavor of an experiment in seeing how small a scripting language can get and still be useful.
The definitive Tcl reference is [JO]. The Tcl world doesn't have one central repository run by a core group analogous to Perl's or Python's, but there are several excellent websites that point to each other and cover most Tcl tool and extension development. Look at URL http://www.tcltk.com first; among other things, it offers Tcl sources of an interactive Tcl tutorial.
Tcl implementations exist for Windows 95 and Windows NT. Tcl/Tk scripts will run cross-platform with GUI capabilities.
[FIXME: Add Tcl/Tk case studies.]
The Python language is a very clean, elegant design with excellent modularity features. It offers designers the option to write in an object-oriented style but does not force that choice (it can be coded in a more classically procedural C-like way). It has a type system comparable in expressive power to Perl's, including dynamic container objects and association lists, but less idiosyncratic (actually, it is a matter of record that Perl's object system was built in imitation of Python's). It even pleases Lisp hackers with anonymous lambdas (function-valued objects that can be passed around and used by iterators). Python can use the Tk toolket to easily build GUI interfaces.
The standard Python distribution includes client classes for most of the important Internet protocols (SMTP, FTP, POP3, IMAP, HTTP) and generator classes for HTML. It is therefore very well-suited to building protocol robots and network administrative plumbing. It is also excellent for Web CGI work, and competes successfully with Perl at the high-complexity end of that application area.
Of all the interpretive languages we describe, Python and Java are the only ones clearly well suited for scaling up to large complex projects with several cooperating developers. In many ways Python is simpler than Java, and its friendliness to rapid prototyping may give it an edge over Java for standalone use in applications that are neither hugely complex nor speed-critical. An implementation of Python in Java, designed to facilitate mixed use of these two languages, is available and in production use; it is called Jython.
Python cannot compete with C or C++ on raw execution speed (though using a mixed-language strategy on today's fast processors probably makes that relatively unimportant). It loses to Perl for small projects and glue scripts heavily dependent on regular-expression capability. It would be overkill for tiny projects, to which shell or TCL might be better suited.
Like Perl, Python has a well-established development community with a central Web site carrying a great many useful Python implementations, tools and extension modules. You'll find it at URL http://www.python.org.
The definitive Python reference is [PY]. Extensive on-line documentation on Python extensions is also available at the Python web site.
Python implementations are available for Microsoft operating systems. Cross-platform GUI development is possible with either Tk or two other toolkits. Python/C applications can be ``frozen'', quasi-compiled into pure C sources that should be portable to systems with no Python installed.
In expert mode, the GUI supports editing of about sixty attributes divided among three panel levels. Attribute widgets include a mix of checkboxes, radio buttons, text fields, and scrolling listboxes. Despite this complexity, the first fully-functional version of the configurator took less than a week to design and code, counting the four days it took for the author to learn Python and Tk.
Python excels at rapid prototyping of GUI interfaces, and (as fetchmailconf illustrates) such prototypes are often deliverable. Perl and Tcl have similar strengths in this area (including the Tk toolkit, which was written for Tcl) but are hard to control at the complexity level (approximately 1400 lines) of fetchmailconf. Emacs Lisp is not suited for GUI programming. Choosing Java would have increased the complexity of the programming task without delivering significant benefits for this non-speed-intensive application.
In Chapter 7 we will re-examine the fetchmail/fetchmailconf pair as an example of one way to separate implementation from interface.
The implementation of PIL illustrates the way Python can be readily augmented with loadable object-code extensions to the Python interpreter. The library core, implementing fundamental operations on bitmap objects, is written in C for speed. The upper levels and sequencing logic are in Python, slower but much easier to read and modify and extend.
The analogous toolkit would be difficult or impossible to write in Emacs or Tcl or shell, which don't have or don't document a C extension interface at all. Perl has such facilities, but they are ad-hoc, poorly documented, complex, and unstable by comparison to Python's and use of them is rare. Java's Native Method Interface appears to provide a facility roughly comparable to Python's.
The PIL code and documentation is available at http://www.pythonware.com/products/pil/.
A few things can be said with confidence. One is that Java is here to stay as a Web-applet language. The precedent set by Netscape and Microsoft Explorer guarantees Java a permanent niche as a vehicle for live content on the Web. This in itself, however, says little about its merits either as a standalone language replacing C or as part of a toolkit for mixed-language development.
In Java's favor, we can say that the language is cleverly designed to capture the huge benefit of automatic memory management and the lesser but not insignificant benefit of OO design, while retaining a broadly C-like syntax that most programmers will find comfortable. We can note that it includes support for callouts to dynamically-loaded C and calling Java as an embedded language from C. And we can fairly judge it superior to C++ (which is both more complex and does less to attack the memory-management problem) for all but systems programming and the most speed-critical applications.
Against Java, we can say that (compared to, say, Python) some parts of it appear over-complex and others deficient. Java's class-visibility and implicit-scoping rules are baroque. The interface facility avoids complex problems with multiple inheritance at the cost of being only slightly less difficult to understand and use in itself. The lack of a type-safe dynamic container object for mixed-type elements (analogous to Perl or Python arrays) is a problem. The lack of a first-class associative-array object (analogous to Perl hashes or Python dictionaries) is another one. And the absence of any facility for conditioning code at compile time (like C's #ifdef/#endif) can be a significant irritant on large, real-world projects.
Furthermore, Sun's handling of the Java language has been both politically and technically obtuse. Java's first GUI toolkit, AWT, was a mess that had to be scrapped and replaced. Withdrawing the language from ECMA/ISO standardization further nettled many developers already upset by features of the so-called "Sun Community Source License".
How Java will compete outside the applet context against the other languages we describe here is unclear as yet, and may depend largely on project scale. We may expect its proper niche to resemble Python's. Like Python, it cannot compete with C or C++ on raw execution speed, nor against Perl on small projects that use pattern-driven editing heavily. It is (more definitely than Python) overkill for small projects. We may guess that Python will have an edge in smaller projects and Java in larger ones, but the verdict of experience is not yet in.
The best single reference on paper is probably Java In A Nutshell [DF]. Trails to all the world's Java web sites begin at URL http://java.sun.com, which also has complete HTML documentation available for download for free.
Java implementations are available for all Unixes and for Microsoft operating systems and support cross-platform portability of all pure-Java programs (including GUI capabilities).
Sources for Kaffe, an open-source Java implementation with class libraries conforming to most of JDK 1.1 and portions of JDK 1.2, are available at http://www.kaffe.org/.
[FIXME: Add Java case studies.]
Nevertheless, there is a range of applications in which Emacs Lisp is more effective than anything else. Many of these have to do with front-ending development tools such as the C compiler and linker, make(1), version-control systems, and symbolic debuggers; we'll discuss these in Chapter 4 The Mechanics Of Development.
More generally, Emacs is to pattern- or syntax-directed interactive editing what Perl is to pattern-directed batch editing. Any application that involves interactively hacking a special file format or text database is an excellent candidate to be prototyped (and possibly delivered) as an Emacs mode (an Emacs Lisp program that specializes the Emacs editor's behavior).
Emacs Lisp is also valuable for building applications that have to be closely integrated with a text editor, or which function primarily as text browsers with some editing capability. User agents for email and USENET news fall in this category. So do certain kinds of database front ends.
Emacs Lisp is a Lisp. It follows as the night the day that it manages memory automatically and is far more elegant and powerful than most conventional language, or indeed most unconventional languages; it can compete with Java or Python on this level and laugh at C/C++, Perl, shell or Tcl. Lisp's perennial problem of lacking a standardized OS binding for portability is solved by the Emacs core, which in effect is its OS binding.
Lisp's other perennial problem, of being a resource hog, is still with us (though less pressingly on modern machines). The main drawback of Emacs Lisp is that it implies a very heavyweight interpreter including the entire Emacs binary. EMACS actually stands for stands for ``Editing MACroS'', but parody expansions like ``Emacs Makes A Computer Slow'' and ``Eventually Munches All Computer Storage'' are common (in fact the Emacs distribution itself includes a list of them).
The definitive Emacs Lisp reference is The GNU Emacs Lisp Reference manual, which may be browseable through your Emacs's `info' help system. If not, it can be downloaded from FSF's FTP site, ftp://prep.ai.mit.edu/pub/gnu. If you find that impenetrable, [WGE] may help.
For more information, see the discussion of Emacs under editors in the next chapter.
Broadly speaking, C and C++ and Emacs Lisp have remained stable across this time period, appealing to much the same constituencies in 2001 as they did in 1997. C has gained slowly at the expense of older conventional languages such as FORTRAN; C++, on the other hand, has lost some ground to Java.
Perl usage has grown respectably, but the language itself has been stagnant for two years or more. Perl's internals are notoriously grubby; it's been understood for years that the language's implementation needs to be rewritten from scratch, but an attempt in 1999 failed and another seems presently stalled. Nevertheless, Perl is still the 800-pound gorilla of scripting languages and dominates web scripting and CGI.
Tcl has been in a period of relative decline, or at least of diminishing visibility. New Tcl releases since 8.0 have added little to its capabilities. In 1996 a widely-reported and plausible estimate of community sizes held that for every Python hacker there were five Tcl hackers and twelve Perl hackers. Today, judging by search results at SourceForge, Tcl and Python have switched places.
As the above indicates, Python has risen in popularity as rapidly as Tcl has fallen. Though the Perl community is still quite a bit larger than Python's, a visible tendency of the brightest Perl hackers to migrate to Python has been rather ominous for the former language -- especially as there is no migration at all in the opposite direction.
Java has become widely used at sites already invested in Sun Microsystems technology and is in increasing deployment as an instructional language in undergraduate computer science curricula (a role for which it is extremely well suited). Elsewhere, however, it is only marginally more popular than it was in 1997. Sun's determination to stick to a proprietary licensing model has prevented the major breakout many observers predicted three years ago, and if anything Java use under Linux and in the wider open-source community may have slightly declined since then.
No new language has emerged to seriously challenge those I've described here. Non-Emacs LISP dialects, a once-promising area that seemed headed for a renaissance in the mid-1990s, have continued to fade. Recent efforts such as Ruby (a sort of Python-Perl-Smalltalk cross developed in Japan) and Squeak (an open-source Smalltalk port) have so far neither attracted hackers far outside their development groups nor demonstrated staying power.