Tricks of the Java Programming Gurus
Alternatives to Java
No language is perfect for every task. It's common for many programmers
to use three, four, or even more programming languages in a week.
Some languages may be necessary for interfacing with other applications
or libraries, and others might have unusual strengths that are
useful for a particular application.
Many applications are written in more than one language, and some developers really like working that way-they write the core functionality in an efficient, highly structured language such as C++ or Java, and then use a more informal, flexible scripting language such as Tcl to add a user interface and glue the pieces together into a polished whole. Because scripting languages are interpreted and are usually more dynamic and flexible than other languages, they are well-suited for building user interfaces that can be tweaked and fine-tuned during usability testing.
It helps to understand what languages might work well with Java
in various situations-knowing the circumstances under which Java
might not be ideal can save a lot of frustration, especially if
you know what languages fit those circumstances better. It's also
nice to know about other languages that share some of Java's characteristics,
if only so you can know how good you've got it being a Java programmer.
(To be fair, the other languages do have advantages over Java
in some situations. Java's biggest strength is an unusual combination
of features in one language, rather than any one particular feature.)
This chapter covers other languages in four groups, moving roughly from lower levels to higher ones. The first group includes "nuts and bolts" languages; they are useful for gaining access to existing libraries and facilities. The second group consists of alternative general-purpose languages, all of which are intended for writing large, stand-alone applications. The third group is comprised of other secure languages, with security features intended for supporting mobile, untrusted programs. The final group, scripting languages, is like the first group in that it consists of languages that would work well alongside Java in a single application. The scripting languages, however, are most useful at the highest levels of the application, rather than the lowest ones.
This chapter should be seen as a survey of languages in several different categories, rather than an explicit comparison. Even where a language might be appropriate as an alternative to Java, rather than as a companion, I've tried to avoid assessing the language's advantages or disadvantages with respect to Java. Bjarne Stroustrup, the designer of C++, has said, "Language comparisons are rarely meaningful and even less often fair." Nevertheless, an implied comparison is present in the choice of languages discussed in this chapter and in the descriptions of their salient features. If any of these languages seem interesting to you, I encourage you to learn about them and form your own opinions. I've included pointers to further information, except in the extremely well-known cases of C and C++.
At the bottom end of an application, it's not uncommon to have to drop into a low-level language to build interfaces to underlying systems or hardware. It used to be even more common than it is now. At one time many, if not most, large, serious applications had to have some assembly language somewhere to perform I/O, hardware interfacing, or other system tasks. Languages such as C and C++, however, which try to fulfill the entire spectrum of programming needs, have proven to be good languages for doing a lot of those low-level tasks, and most recent operating systems have implemented C bindings to their low-level interfaces. Programmers writing in those languages could usually avoid resorting to other languages.
Recently, however, as applications have grown larger and more complicated, programmers have been moving to higher-level languages, which are more formal and highly structured, to help manage the complexity of very large projects. Typically, such languages don't provide the kind of fine control for nuts and bolts tasks that languages such as C and C++ do. Additionally, there are many libraries and application APIs (such as database APIs, for example) that are designed for access from C. For these reasons, the practice of writing key portions of an application in a more machine-oriented, less-abstract language is becoming more common again-this time, with C and C++ filling the role that was formerly held by assembly language.
In Java, methods written in a lower-level language are called native methods. The native method interface is designed and specified for C (although C++ can also be used). Interface libraries might appear that permit writing native methods in other languages, but C and C++ are still the languages of choice for such tasks.
Because C and C++ are so well-known, there's little new to say
about them as alternatives to Java. There's so much to say about
their use for native methods and about converting existing code
from those languages to Java, however, that the topic is covered
in other chapters. See Chapter 28, "Moving
C and C++ Code to Java," and all of Part 9, "Native
Methods: Extending Java
There are several other general-purpose languages that share many of Java's strengths for general application programming. Structured, object-oriented, and portable languages have been the focus of a great deal of effort and interest during the past five to ten years. Not all of these languages are new, but they all share Java's orientation toward "programming in the large," with features that are intended to help manage the complexity of large software projects.
Modula-3 is a relative of Modula-2. It is not truly an extension of Modula-2; although many new features have been added, more have been removed, resulting in a simpler language. In that respect, Modula-3 resembles Java, which is also simpler than the languages to which it is most closely related.
Modula-3 was designed for programming large applications, but it is also meant to be suitable for low-level system tasks. To that end, it takes an interesting hybrid approach to some issues. A programmer can manage storage for some objects explicitly, while allocating others on a garbage-collected heap. Modules can be designated "safe" or "unsafe"; the compiler prohibits certain dangerous operations in unsafe modules.
The core of Modula-3 is its innovative type system. Modula-3 maintains strict separation between the interface definition of a module and its implementation. Modules are used as namespaces and units of protection, similar to the way packages are used in Java. Modula-3 provides ways to control precisely how much information about a type is made available outside its module, and subtypes can be used to either extend or restrict an existing type. Modula-3 is object-oriented, but not exclusively: Classes represent just one part of the Modula-3 type system.
The Modula-3 library is extensive, with thread support, many data structures, network support (including versatile support for network objects and object migration), and a window toolkit. The window toolkit is more mature and versatile than the AWT, although it is not as portable; it currently runs under X and is being ported to Windows 95 and Windows NT.
Modula-3 is portable roughly in the same sense that C is. It is a traditional compiled language and makes little attempt to hide system differences such as filename syntax. Implementations exist for various UNIX systems, DOS, Windows 95, and Windows NT.
The Modula-3 home page can be found at the following address:
Eiffel is a compiled, object-oriented language based on the principle of "design by contract." This idea extends the idea of class interfaces to provide some guarantees of behavior. Eiffel programmers are encouraged to think of code that uses a class as a client of the class, and to formally describe the commitments that the class makes to clients (and as with any contract, reciprocal conditions that the client must uphold).
An example might help to make this clear. This example is a simplified version of one in Bertrand Meyer's book Eiffel: The Language (Prentice Hall, 1992). Consider a class-part of a banking system-representing a bank account. If you are a user of that class, you want some guarantees of certain things-for example, if you withdraw five dollars, you expect the balance in the account to drop by five dollars and no more. However, the class can guarantee that only under certain conditions; you must have at least five dollars in the account, for example.
Most object-oriented programming languages enable programmers to separate the interface and implementation of a class. Eiffel makes contractual conditions a part of the interface. Methods can have preconditions, which are conditions that must be true when the method is called (the client must ensure that these conditions are satisfied). Methods can also have postconditions, which must be true when the method returns. Postconditions are the guarantees that the class makes to a client if the client's end of the bargain is met. Entire classes also can have invariants, which are general consistency constraints that the class guarantees. Invariants must always be true except when one of the methods of the class is actually executing.
Here's an example of the account class, with only the withdraw method specified:
-- This is Eiffel, not Java!
class AccOUNT feature
minimum_balance: INTEGER is 1000;
-- Several methods omitted here
withdraw (sum: INTEGER) is
-- Withdraw sum from the account
-- This is a precondition. If our client has called us correctly,
-- sum will have a non-negative value, and we will be able to
-- withdraw sum from the account without going under
sum >= 0 ;
sum <= balance - minimum_balance
-- This is a postcondition. If our client obeyed all of the
-- preconditions, we guarantee that the new value of balance
-- will be the old value minus sum.
balance = old balance -- sum
end; -- withdraw
-- Several methods omitted here
-- This is an invariant condition. We guarantee that balance will
-- never be less than minimum_balance, except perhaps during
-- the execution of one of our methods.
balance >= minimum_balance
end -- class AccOUNT
The language runtime system can check the conditions as the program is running, raising an exception if a condition is violated. There's some overhead involved in that, of course, so frequently the checking is used primarily during debugging and testing, and it is disabled in production systems.
All code has such guarantees and restrictions, but they are usually informal. Because few languages have the kind of explicit support that Eiffel does, information about proper usage has to go in the documentation of a class, so naturally it is often forgotten. Most programmers have had the experience of reading the documentation for a library routine and thinking something like, "Okay, but what happens if I try to withdraw zero dollars? Does it do the right thing, or does it blow up?" Usually, the programmer has to write a test program to find out, and even then, there's no guarantee that the routine was designed that way-it could just be an implementation artifact that could change in the next release of the library. Eiffel's explicit support for contractual design doesn't keep developers from forgetting to specify conditions, but it is a useful feature nonetheless.
Eiffel also differs from Java in supporting generic classes (which are similar to C++ templates) and multiple inheritance. Eiffel is uniformly object-oriented; all values are instances of some class or another. Unlike Java, Eiffel supports object values that are not references, so it's possible for objects to contain other objects, rather than simply pointing to them. Implementations of Eiffel usually provide garbage collection, although the language specification does not require it. Eiffel supports exception handling.
Eiffel implementations also usually come with a large class library. Some parts of the library are standard, but others are specific to a particular implementation. Interestingly, the standard Eiffel library provides a form of persistence, although it differs from the orthogonal persistence facility being developed for Java (see Chapter 19, "Persistence").
You can find one good source of Eiffel information on the Web at the following address:
Common Lisp (and CLOS)
Common Lisp is a standard dialect of the Lisp language that is available in industrial-strength, compiled implementations. Lisp has historically been used primarily by the artificial intelligence community (and offshoots such as the expert systems industry). Lisp has a strong reputation as a good vehicle for the implementation of extremely large, complicated systems.
Lisp has always been a permissive language, with untyped variables and dynamic, loose binding. Programmers can, for example, arrange for the implementation of a function (even a built-in function) to change while a system is running, and that is a reasonably common programming technique. Common Lisp enables declarations that can tighten some of those rules (and permit more efficient compilation), but they are optional. Lisp is still a loosely typed language.
The Common Lisp Object System (CLOS) is an object facility built on Common Lisp. CLOS supports multiple inheritance. Like the Lisp language, CLOS is dynamic and flexible, even at runtime. Objects have slots, which are the equivalent of instance or class variables. Often, slots are not accessed directly, but rather through accessor functions (separate accessor functions are used for reading and writing a slot). If an accessor function for writing a particular slot has not been defined, that slot is protected. Because accessor functions, like any other Lisp functions, can be supplied by the programmer, they can be customized to perform special functions.
Unlike most object-oriented languages, CLOS does not have a special syntax for method calls on an object. Instead, CLOS is based on a special kind of function called a generic function. You can think of a generic function as a composite function that contains many specialized functions, along with rules for how to choose between them. When a generic function is called, it examines the types of all its arguments, finds the right specialized function to call for that particular combination of arguments, and calls it. Thus, generic functions can work as method calls do in other object-oriented languages, selecting the right method among several with the same name based on the types of the arguments. That explanation is slightly oversimplified, but it's a reasonable approximation of the way generic functions work.
The most unusual and fascinating aspect of CLOS is the way it carries forward the Lisp tradition of dynamism and permissiveness. A class can be changed at runtime, even if instances of the class already exist (existing instances are updated automatically to fit the new definition). Similarly, individual instances can be changed from one class to another.
Coupled with the accessor functions, these dynamic features can be extremely valuable for changing long-running systems on-the-fly. The CLOS specification describes a simple example where a position class is created to represent (x, y) positions on the Cartesian plane. Suppose that, after the system is put into production, it is discovered that in this particular system it is more useful, and far more common, to describe positions in terms of polar coordinates. Using CLOS, the position class can be changed to represent positions as (rho, theta) pairs to make the most common case more efficient. The old accessor functions for x and y can be retained so that existing code will still work properly, but instead of storing in and retrieving from slots in the object, the new versions of the accessor functions will dynamically calculate x and y based on rho and theta.
It's probably unfair to concentrate on this loose, permissive aspect of CLOS programming-typical Common Lisp code is far more disciplined. The dynamism of CLOS is one of its most interesting facets, however, and there are situations where it is valuable.
Common Lisp supports exceptions, and it has a large variety of useful data types-some built in, some supplied by the library. The ease with which extremely complicated data structures can be represented in Lisp has always been one of the language's great strengths, along with its excellent support for high-level mathematics. Common Lisp also has a large standard library of useful functions.
The largest repository of Common Lisp information on the Web is at the following address:
Dylan is a new language developed recently at Apple. For the time being, Apple has stopped work on Dylan, but other groups (including one commercial venture) are continuing to use it and build implementations.
Dylan was intended to be a dynamic language in the tradition of Lisp, but with more uniformity and control. (The name "Dylan" comes from "dynamic language.") It has many similarities to CLOS, including untyped variables (type declarations are optional), dynamic binding, slots with accessor functions, generic functions, multiple inheritance, first-class function values, and anonymous functions. It also differs from CLOS; the syntax is more conventional, the language is not quite so permissive (objects cannot change their class, for example), and programmers can "seal" certain class features so that they cannot be modified or overridden (similar to Java's "final" declarations). Like Eiffel and Smalltalk, Dylan is object-oriented "from the ground up," with all values being instances of a class type.
Dylan was designed to be much easier to compile efficiently than CLOS. It also was designed to be simpler, without sacrificing the dynamic characteristics of Lisp, which the Dylan designers believe to be very important for building large, complex systems.
Originally, Dylan had a Lisp-like syntax, but the designers changed the syntax to a more conventional, Algol-like style in response to early user feedback. The result is, in my opinion, pleasant and easy to read, while retaining a "Lisp-ish" feel due to the philosophy of the language. For example, Dylan methods can return multiple values, and the language supports a handy mechanism for assigning those values to variables in the caller's scope. Here's a short example:
// This is Dylan, not Java!
// First, define a method that returns three string values:
define method full-name (customer-id)
=> (given :: <string>, middle :: <string>, family :: <string>);
// Look up the name somehow based on the customer id,
// storing the pieces in given, middle, and family ...
// Now return the three parts of the name:
values(given, middle, family);
end method full-name;
// Now call the method and collect the values:
let (first, middle, last) = full-name(12345);
Information about Dylan, including the reference manual, can be found at the following address:
Researchers at Carnegie Mellon University maintain another helpful Dylan page:
Like C++, Smalltalk is a direct descendant of Simula, the original object-oriented language. However, Smalltalk and C++ were designed with very different goals. Smalltalk was designed by researchers at Xerox Palo Alto Research Center in parallel with their exploration of the basic ideas and mechanisms of object-oriented programming. Smalltalk is one of the purest of object-oriented languages: All operations in the language, including basic arithmetic, variable assignment, and control structures, are accomplished by methods executing in the context of objects. Even code blocks, such as method bodies, are represented as objects. This purity might seem extreme to programmers more accustomed to the traditional procedural programming model, but it was one of the ways that the researchers forced themselves to explore the limits of their new ideas. The resulting language is extremely powerful and very pleasant to use (although procedural programmers must learn to think about some programming concepts in a new way before feeling really comfortable programming in Smalltalk).
Like Java, Smalltalk is more than just a language-it is a platform for programming. Smalltalk has always been defined in terms of a virtual machine, and it has a large library of predefined classes for data structures, windows, and graphics-most of the same things the Java library provides. Like many of the Lisp dialects, Smalltalk also incorporates a development environment, with a class and method browser, a debugger, and so on.
Smalltalk's syntax and completely pure object-oriented basis are unique among major programming languages, but in many other respects Smalltalk is similar to Lisp. Although values are typed, a given variable can hold a value of any type. It is interpreted and dynamic, so that any part of the system can be modified or replaced while the system is active.
Although Smalltalk doesn't have a particularly high profile, it is commonly used in several communities, most notably the financial industry.
A good starting point for learning about Smalltalk is the following page:
For large, complicated programs, the structure, encapsulation, and type checking provided by the general-purpose languages described previously can be very helpful. Those features can help developers manage complexity and localize errors, and they can permit the compiler and other software tools to catch many kinds of errors. For smaller programs such as prototypes or user customizations, on the other hand, such features often get in the way. Those kinds of programs are more appropriate for scripting languages.
Scripting languages are usually untyped, permissive, interpreted languages. Simple programs can be written very quickly. Experimental prototypes can be built up gradually and changed with ease. Scripting languages might be used for small throwaway programs or for prototypes. They are also useful for providing user-level customization and configuration facilities, and some developers find them helpful for building portions of their programs (such as the user interface) that need to be dynamic and adaptable in response to user feedback. To support such uses, scripting languages are often embeddable, meaning that interpreters for the scripting languages can be linked into an application written in some other language. This section covers several popular scripting languages, with an emphasis on their role in user interfaces and user-level customization facilities. (Chapter 29, "Using Tcl with Java," contains an in-depth discussion about using a scripting language with Java.)
The name Tcl stands for "tool command language," and it reflects Tcl's original goal: to be a common, reusable, application-neutral scripting language for applications. It is implemented as a C library that can be linked into an application, and a Java interface is available.
Tcl is extremely simple, and because it was designed to work with applications, it provides general functionality, such as variables, simple data structures, string and number manipulation, and control structures (including error handling). These features provide a neutral language framework for special-purpose extensions. The language also provides I/O facilities (including networking support) and some operating system interface features.
Like many scripting languages, Tcl represents values as strings. Tcl is oriented around commands, and extensions consist of sets of new commands that are added to the language. Applications that embed Tcl create new commands to provide access to application functionality. There are also many general-purpose extension packages available. The most popular of them is Tk, a GUI toolkit. Tk is so useful that although it was designed as a Tcl extension, interfaces have been written so that Tk can be used from several of the other scripting languages listed here (Perl, Python, and Scheme).
Tcl runs on Windows, Macintosh, and most UNIX systems. Here is the Tcl home page:
Unlike Tcl, Perl was not originally designed as an application scripting language; it was designed as a stand-alone scripting language for writing powerful utilities quickly, especially where those utilities involve text manipulation. The name stands for "practical extraction and reporting language" (although the name came before the acronym), and Perl's powerful parsing and text manipulation facilities have made it a favorite for Web-based applications, where the protocols involved (such as HTTP and HTML) are text-based.
Perl's designer, Larry Wall, drew features (both syntactic and semantic) from several UNIX languages, including the Bourne shell, sed, awk, and C. It's a strange, hodgepodge language in many ways, but somehow Wall pulled together all those disparate elements and made them work. The syntax is intricate and complex, but most people who spend a little time learning it have no problem with it (perhaps for the same reason most people don't have serious trouble even with complicated, irregular languages such as English). It's certainly possible to write extremely confusing code in Perl, but with just a little discipline and thought, Perl programs can be very easy to read. Like most scripting languages, Perl is very permissive, but where other scripting languages tend to strive for simplicity, Perl aims for expressiveness.
For many, the distinguishing feature of Perl is its reliance on regular expressions for parsing and string processing. Regular expressions are expressions in a powerful pattern language, and programmers can use them compactly to describe extremely complicated patterns in text. Other scripting languages (including Tcl, Python, and Telescript) support regular expressions, but Perl integrates them into the language rather than providing them through library routines. That integration is the source of much of Perl's text processing power. The primary drawback of regular expressions is that they can be cryptic, although recent releases of Perl include new features to help make regular expressions more comprehensible.
The current version of Perl is called Perl5, and it is a big improvement over its predecessors. The syntax has been simplified and regularized in some ways, without serious loss of compatibility or expressiveness. An object-oriented style of programming is supported, as is a versatile module mechanism, which has fostered an explosion of new modules specialized for various tasks. The new Perl interpreter is embeddable so that it can be used as an application scripting language, although its syntax may be intimidating for nonprogrammers. Perl can be extended in C, if necessary.
The starting point for Perl information on the Web follows:
Python is a scripting language designed by Guido van Rossum. Whereas Tcl was designed specifically as an application scripting language and Perl was designed for text handling tasks, Python was designed as a general-purpose language for "throwaway" programs and rapid prototyping. For many tasks, C is too low-level and primitive, but the available quick-and-dirty languages such as the UNIX shells are too quick and dirty. They quickly become unwieldy if the program grows larger (or more important) than anticipated. Python was invented to fill the gap.
In most ways, Python is a fairly typical scripting language: It is permissive, and it has common control structures, procedures, and useful data structures such as associative arrays. Python also has object-oriented features and a rich class library.
Python's most unusual characteristic is its syntax. For the most part it looks conventional, but statements are grouped by indentation instead of begin and end delimiters or curly braces. Here's an example from van Rossum's Python tutorial, a small loop that searches for prime numbers up to 10:
# This is Python, not Java!
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print n, 'equals', x, '*', n/x
# This "else" belongs to the for loop; it will be
# executed if the loop finishes naturally, but not
# if the "break" statement is called ...
print n, 'is a prime number'
It seems that few programmers are neutral when it comes to grouping statements by indentation; they either love it or hate it. Python has a large number of devotees, however, and it has been used to build some impressive software, including a Web browser called Grail.
Like Tcl and Perl, Python can be embedded in an application or extended by using C. Here is the Python home page:
For the most part, VBScript is Visual Basic with a lot of things removed. There are too many differences between the two to list here, but the features that have been removed are mostly data types and library routines. The result is roughly equivalent in complexity to the other scripting languages mentioned here.
VBScript's Basic heritage makes it a weaker language than most of its competitors, but that might not be a serious handicap. Certainly a huge number of useful applications have been written in Visual Basic, and most VB users find it a productive language in which to work. There is no reason to suspect that VBScript will be any different.
More information about VBScript is available at the following address:
Scheme (and GUILE)
It was difficult to decide where to discuss Scheme in this chapter. At least where theory is concerned, Scheme might be considered the queen of programming languages: It is small, pure, and beautiful. Where practicality is concerned, there is more room for debate. Many programmers love Scheme, but it is not widely used.
Scheme is a small dialect of Lisp, simpler than most Lisp dialects, but still very powerful, due to a carefully chosen combination of features. That same small set of features makes it possible for compilers to do a good job of making Scheme efficient.
Scheme can be grouped with scripting languages for three reasons:
- It is frequently proposed as a useful scripting language, and some Scheme implementations have been built specifically for that purpose.
- One current Scheme project, GUILE, is promoting Scheme as a common scripting language upon which other, more conventional, scripting languages can be implemented.
- A small Lisp implementation has proven to be extremely useful as a scripting language in what is probably the most configurable and customizable program ever written, the GNU Emacs text editor. Emacs Lisp is not available as an independent, embeddable interpreter, but Scheme is a reasonable alternative.
One disadvantage of Scheme as a scripting language is that, in the role of user-level customization languages, it can be daunting for nonprogrammers. Additionally, there are many implementations of Scheme and no common, standard library of Scheme functions. Nevertheless, Scheme has undeniable power, it is extremely simple, and it can be very efficient.
If Scheme interests you as a scripting language, you can find a large repository of Scheme information at the following address:
Enforcement of security used to be the job of operating systems, but with the growing importance of the Internet and the current interest in mobile or dynamically downloaded programs, several languages have implemented security features of their own. Java isn't the first such language, nor is it the last. This section describes some other secure programming languages. In two cases, the secure languages are special versions of languages we've already discussed (Tcl and Perl).
Safe-Tcl is a secure version of the Tcl language, originally designed for sending applet-like programs in electronic mail, but applicable to other tasks as well. Safe-Tcl has been incorporated into the core Tcl library.
Tcl permits multiple interpreters to exist in a single application and to communicate in controlled ways. Safe-Tcl works by designating one or more interpreters as "safe": Potentially dangerous commands are removed from safe interpreters. Tcl applications can loosen the security of a particular safe interpreter by reinstalling particular commands or by providing other commands that check arguments and conditionally enable access to sensitive resources.
Tcl is designed to be extensible, and Tcl is unusual in that it explicitly integrates extension packages into its security model. An extension can be loaded in a "safe mode," in which it will only register extension commands that are safe. If a locally installed extension does not support the safe initialization mode, Tcl refuses to load that extension into a safe interpreter.
Tcl does not yet provide an authentication framework for verifying the origin of untrusted code.
Obliq is a novel new language written in Modula-3 and strongly
influenced by some
Modula-3 library facilities. Obliq is designed to make it easy to develop distributed programs, and its security facilities arise naturally from its design, rather than being added on later.
Obliq is designed around processes that can migrate from one site to another. When a process migrates, its variables continue to refer to objects at the original site, and references to those objects are transparently accomplished via network transactions. Processes can make calls to each other across the network and pass each other entire objects (which migrate to the site of the new process) or just references to stationary objects.
Just as functions in C can access only their own local variables, global variables, and values that have been passed in as parameters, Obliq functions and methods can access only their own local variables, global variables at their originating site, and values that they've been given. A process arriving at a new site cannot access any object at that site unless it receives that object in a call from another process.
This "distributed scope" is the basis for security in Obliq. For example, file operations require the use of a file system enabler object. A process can access the file system enabler object at its originating site via the global variable fileSys. When the process migrates to another site, fileSys still refers to the enabler object back at the original site. The process cannot access the file system enabler at the new site unless some other process passes it as a parameter. In addition to this all-or-nothing security, specialized versions of enablers can be created to provide restricted, conditional access to a resource.
Obliq shares many of the characteristics of scripting languages: It is an interpreted language with untyped variables and high-level data structures. It has an extensive library, built on the Modula-3 library. Obliq can be embedded in Modula-3 programs as a scripting language.
Because Obliq is such a novel language, describing it is difficult in this small space. Obliq has a home page at the following address:
It is well worth a look.
Telescript may well be the first secure programming language you ever encountered, although you may not have realized it at the time. Telescript is a secure language developed and sold by General Magic, along with their Magic Cap operating system for personal digital assistants. Telescript is the basis for some of the Magic Cap communication features, such as "active invitations."
Telescript bears some resemblance to C++ and Java, but there are many differences. The most interesting aspect of Telescript is not the language itself but the application framework that is supported by the Telescript library. The framework is based on mobile agents and stationary places. Agents travel between places, sometimes meeting other agents, sometimes simply interacting with the facilities available in a place. The idea is that agent programs can wander the network doing work on your behalf, like trying to find the cheapest fare to your vacation destination, or surveying your friends to find a time when everyone is free to meet for a pizza.
Of course, a similar application framework could be built using other secure languages, including Java. It would be fairly easy to build a similar facility using Obliq's more general model of migrating processes. Now that more open systems such as Java are available, Telescript's future looks less certain than it once did.
Telescript's security model is somewhat complex, with different kinds of resources being controlled in different ways. However, the model is unusually thorough. In addition to the yes-or-no restrictions provided by Java, Telescript also supports setting quotas for consumable resources such as memory or CPU time. An agent can also impose stricter limits on itself; for example, an agent might reduce its own CPU time allowance slightly to ensure that it holds enough time in reserve to be able to migrate back to its originating site without losing information.
General Magic maintains a Telescript page at the following address:
Like Tcl, Perl permits applications to construct secure environments for the execution of trusted code. The mechanisms are very similar, except that a Perl package is used (instead of a complete interpreter as in Safe-Tcl) to define the boundary of the secure environment. Just as in Safe-Tcl, the application can selectively loosen the security restrictions by placing "wrapper" procedures around unsafe operations.
Penguin is the beginning of an application framework for Safe-Perl. Penguin provides higher-level interfaces for creating and configuring secure environments and a cryptographic signature mechanism (based on PGP) for identifying the source of untrusted programs. More information about Penguin can be found at the following address:
There are, of course, far too many programming languages. "The Language List" (http://cuiwww.unige.ch/langlist/), a list of known programming languages compiled by Usenet denizens, currently contains over 2,000 entries.
However, none of the existing languages are perfect, so there will be more. Like human languages, programming languages don't exist in isolation. Java must interface with nuts and bolts languages and make good use of scripting languages. As for other secure languages and general-purpose languages, Java must both cooperate with them and compete against them. All the languages listed in this chapter represent serious attempts to solve real software development problems. With the exception of the secure languages (which are breaking new ground), they all have proven their worth and gained strong followings, at least within certain communities. When you need to venture beyond Java-and you certainly will at times-choosing the right companion or alternative can be the key to success.