Roger E. Masse
Corporation for National Research Initiatives
November 26, 1996
If you believe the industry hype, within a year, Sun Microsystems' Java will not only be the language of choice for programming the World Wide Web, but also the first tool developers reach for in other more general-purpose programming areas dominated today by C and C++. Being derived from C++, with the addition of garbage collection and the removal of pointers, Java has many features to make developing and debugging programs easier. It's not difficult to imagine hordes of C++ programmers, tired of their languages' idiosyncrasies and bulk, moving to Java, just as they moved from C++ from C, when they discovered the benefits of object orientation.
Python is an elegant, general-purpose, object-oriented scripting language that is freely available for anyone to use for any purpose. Being interpreted, Python has no need for a separate compiler and much less need for a formal development environment. Python is a concise very-high-level language. A typical program requires less then one-third the amount of source code than any of the C derived languages, including Java. Python offers programmers conciseness, simplicity, and the short test cycle benefits of an interpretive environment. These features combine to enable rapid prototyping with more building and less writing.
No one language should be all things to all software
engineers. As possible next-generation languages, both Java and
Python bring many new capabilities to developers that increase
productivity. In contrast, each has aspects that are relatively
weak when compared with other languages. This paper explores some
of the merits and drawbacks of each language, for a number of
different application areas, with the intent of proving each to
be a worthy addition to the pool of software engineering tools.
This paper explores the capabilities and shortcomings of two modern languages. This analysis will mainly focus on technical attributes and application areas while staying away from religious issues and hype. If the commentary seems a bit cynical at first, it's only in an attempt to expose ungrounded claims and empty comparisons. The technical issues explored attempt to expose some truth in usability with these two languages.
After some brief introductory material for each language, the paper proceeds to comment on specific language features in an attempt to whet the appetite for further exploration in one of the many excellent referenced sources. While the majority of the discussion is on language capability, the final sections of the paper explore some application areas where Java and Python can be aptly applied.
Java is a new language that borrows basic syntax from C, some keywords from C++, and an object model from Objective-C. Many of the primitive data types and control flow constructs found in C and C++ can also be found in Java. While much of the language looks familiar, the core language is quite different from its descendants. There are no pointers or any way to reference the address of an object or attribute of an object in Java. Method parameters are passed by reference to alleviate this inconvenience. Much of the object-orientation and run-time behavior in Java is borrowed from Objective-C (Gosling, 1995, p12,19,54) Like Objective-C, Java is strongly typed and features late-binding of attributes. This means the location of the code of an object is determined at run-time and so may be dynamically loaded, perhaps over the network.
The classic Hello World program (Ritchey, 1995, p130) in figure 1 displays the some of the basic syntax.
class HelloWorld { public static void main (String args[]) { System.out.println("Hello World!"); } } |
This source code would be typically save as a text file with a .java extension and compiled into byte-code with the command: javac HelloWorld.java. which writes the output to HelloWorld.class. The byte-code file will be executed by the Java interpreter with the command: java HelloWorld. This is slightly different than the Python approach where the compilation and execution phases are both done by the Python interpreter.
Java is strictly an object-oriented language. Procedural programming not contained in class definitions is not supported. This organization encourages programmers to focus on data abstraction with the procedures being the methods that operate on an object's data. This way of thinking is typically reserved for medium-to-large sized applications where the benefits of object-orientation can be felt. Small applications may be unnecessarily cluttered and over-engineered from this force-feeding of object-orientation.
The class-inheritance model of Java differs vastly from C++ and is more easily compared with Objective-C. Like Objective-C, all classes are derived from a single root class Object. Referencing attributes of objects differs from the message oriented Smalltalk syntax of Objective-C (i.e [object message] ). Instead, both Python and Java attributes are referenced with a dot notation and so would appears as: object.attribute.
The Hello World program provides some clues as to the strongly typed nature of Java. In Java, you must declare the type of all variables explicitly before they can be initialized. The number of arguments to methods and their type must be known at compile time as well. There are no variable-length argument lists (Flanagan, 1996, p47). While these restrictions seem somewhat cumbersome when compared to C, the designers of Java claim that these features reduce type and argument mismatch errors. Python, on the other hand, is dynamically typed and statically scoped. Variables are created as they are assigned-to with the type of the object on the right-hand-side of the assignment statement.
Java has very strict rules about automatic type coercion. Code cannot be written that turns an arbitrary integer into an object reference by casting (Gosling, 1995, p49). By sticking to this rule, the designers of Java have one less thing to worry about in terms of security.
Unlike C or C++, Java supports late binding. Attributes of objects are resolved at run-time not compile time. Like Objective-C, the referenced attribute is first searched for in the context of the current class and if not found the search continues up the inheritance chain all the way to class Object. In Python, the binding of attributes to objects is also late. Since Python supports multiple-inheritance, the search traversal is within an inheritance tree. Attributes of Python objects that are instantiated from classes that are derived from multiple classes, goes in a depth-first, left-to-right fashion.
The current Java run-time lacks some of the features that make dynamic binding such a treat in Objective-C. In Objective-C there are many more convenience methods that are bound to the root of the inheritance tree, which in turn are inherited by all classes (Pinson, 1991, p84). Each method of an class has a particular signature which corresponds to a message at run-time. A selector is a hashed value of the method's signature. In Objective-C, using the method respondsTo (and passing a selector), a programmer may ask an instance, at run-time, if an object responds to a particular method. Taking this powerful aspect of Objective-C further allows the programmer to easily establish a responder chain of objects and designate the first responder in the chain as the target for a message. If the first responder does not respond to a message then the message is passed down the chain until an object responds. Such a powerful capability would be a nice addition to the Java run-time and would increase the dynamism and flexibility of it's object-model.Both Java and Objective-C have similar solutions for their lack of multiple-inheritance (Gosling, 1995, p54). Each language defines a way to collect a set of method definitions under a single declaration. Objective-C calls these collections a protocol while Java calls them an interface. In Java, classes may include an interface when declaring the attributes of the class but, unlike with languages that support multiple-inheritance, the class must provide the code to implement the methods defined in the interface. Python has no need for protocols or interfaces because of it's support for multiple inheritance.
Java is free from the memory deallocation problems that face C and C++ by the addition of garbage collection. Instead of the basic reference counting scheme found in Python or inheriting reference counting machinery from the base object as in Objective-C, the Java garbage collector releases all resources that your program no longer references automatically. When compared to C or C++, this is a nice feature that frees programs of much ancillary code and potential memory management coding errors. In order for the garbage collector to not slow down the Java run-time, the Java run-time supports threads. The garbage collector runs as a low priority thread in the background. Under certain circumstances, the default Java garbage-collector may not keep up. Memory intensive application programmers may find themselves having to explicitly manage the garbage collection from their program. Garbage collection in Java is like a car with an automatic transmission you may still have to shift manually on steep hills.
Java is perhaps the most hyped language in history. Sun positions Java as: "A simple, object-oriented, network-savvy, interpreted, robust, secure, architecture neutral, portable, high-performance, multithreaded, dynamic language". Many reference books on Java (Ritchey, 1995, 14-20; Lemay, 1996, p7-9) have at least one section that that make assertions like: "Java is Portable", "Java is High-Performance", and "Java is Simple". The remainder of this sub-section explores some of these claims in detail.
Java is interpreted. The Java interpreter supports the execution of a standard set of predefined byte-codes within a standard execution environment called the Java Virtual Machine (Kramer, 1996, p6). This is the portability model that Javasoft would like to make into a standard. Java programs are as portable to the Java Virtual Machine as the ls command is portable to the UNIX operating system.
The real portability question should be, "How portable is the Java Virtual Machine?" The real answer is probably, "As portable as Javasoft wants it to be". Java is a commercial venture. There appear to be a lot of resources and money working to make Java widely used. One can expect that the Java Virtual Machine will appear as a standard component in many commercial operating systems much like the TCP/IP protocol is today. If this comes to pass, it will be as a result of massive investment on the part of JavaSoft. Because the Java Virtual Machine has a clearly defined specification, research and freeware versions have begun to appear (Hjersing, 1996; Emery, 1996).The technical portability of the Java Virtual Machine lies in the resources it requires from the underlying operating system. Java programs are threaded. When execution begins at least two threads are spawned, one to execute your program, and another low priority thread to run the garbage collector. Unfortunately, there are many operating systems being used today that do not have reasonable threads support. Perhaps this is why JavaSoft currently only distributes Java Developer Kits for Solaris (Intel and Sparc), Microsoft Windows 95 or NT (Intel), and MacOS.
Java is interpreted. The Java Virtual Machine, turns byte-code into machine instruction code. Java is not high-performance when compared to C. It wasn't designed to be. Figure 2 is an example Java program that measures how fast methods can be called.
import java.util.Date; class BenchMark { public static void main (String argv[]) { System.out.println("Start Time: " + new Date().toString()); int i; Nothing bar; bar = new Nothing(); for (i = 0; i < 100000000; i++) bar.foo(); System.out.println("End Time: " + new Date().toString()); } } class Nothing { public static void foo () { return; } } |
C:\users\rmasse\java\BenchMark>javac BenchMark.java C:\users\rmasse\java\BenchMark>java BenchMark Start Time: Fri Oct 04 22:39:00 1996 End Time: Fri Oct 04 22:42:46 1996 |
#include <stdio.h> #include <time.h> main() { time_t now = time(NULL); int i; void foo(); printf("Start Time: %s\n", ctime(&now)); for (i = 0; i < 100000000; i++) foo(); now = time(NULL); printf("End Time: %s\n", ctime(&now)); return 0; } void foo() { return; } |
C:\users\rmasse\MSC\BenchMark\Debug> Benchmark.exe Start Time: Fri Oct 04 22:46:33 1996 End Time: Fri Oct 04 22:46:55 1996 |
The results show roughly 600,000 method calls per second on a 100Mhz Pentium running Windows NT. In contrast, figure 3 shows the comparable program written in C able to call roughly 4.5 million functions per second on the same machine. The raw performance difference approaches an order of magnitude.
The designers of Java, anticipating developers may need C-comparable performance, designed Java with a type system that would allow straightforward compilation to machine code. About ten years ago, Peter Deutcsh discovered a clever way to make Smalltalk run faster. He called it dynamic translation (Lemay 1996, p432). JavaSoft calls it just-in-time (JIT) compiling.Both of the latest versions of Internet Explorer and Netscape Navigator contain JIT compilers for Windows NT and 95 on Intel. The JIT compilers convert Java applet byte-code on-the-fly to machine code. The claimed performance is roughly the same as native C or C++, once the on-the-fly compile is complete. An independent software test conducted by Pendragon Software reports best case comparisons at around a factor of 80 and the average increase being above a factor of 10 when compared using the CaffeineMarkTM 2.01 benchmark suite (Pendragon, 1996). Java can be fast, when it's compiled. With the help of JIT compilers the Javasoft claims of high performance be met. JIT compilers have great potential for Java performance gains. Only time will tell if they become available on a wider variety of platforms.
This is a totally different approach than the one Python takes. Since no compilers exist yet for Python, it is distributed with and is extensible by modules built from code compiled from C or C++ (Watters, 1996, p7-8). This insures that code needing native speed runs fast.
As mentioned earlier, Java supports dynamic or late binding but is statically typed. This was a design decision to aid in discovering more problems at compile time. Unlike C++ or Python, Java is much more like Objective-C when it comes to lack of flexibility with its use of operators. Neither Java (Ritchey, 1995, p41) or Objective-C (Nghiem, 1993, p7) support operator overloading. New types in Java may not define how they interact with the language's defined operators.
Java's type system imposes much more stringent requirements on the developer than even C or C++. For example, classes and method references can not be passed as parameters to methods. In other words, neither classes nor methods are first-class entities. Passing a method as an argument attempts to make a static reference to an attribute that is resolved at runtime. The method's entry point is not known at compile-time. This is quite different than Python where all types are objects and all objects are first-class entities (Lutz, 1996, p19).
Java may have aspects of simplicity, such as behind-your-back garbage collection and no pointer complexities, but the language's overall feel is not one of simplicity. There is a fairly elaborate class protection mechanism which involves five protection levels that control attribute visibility in packages (a collection of related classes), classes and subclasses. Java provides two ways of defining new types. One can inherit from a super-class or define an interface. A class may implement as many interfaces as it wishes providing some of the power of multiple-inheritance without the confusion of multiple base-classes. As Nicolaou observes (Nicolaou, 1996, p3), it is unfortunate that the class mechanism does not prevent sub-classes from introducing new methods inside class bodies. To have done so would have truly separated sub-typing from implementation inheritance. The single-inheritance class mechanism provides both. Judging by the way the Java Developer Kit libraries are implemented, it seems that creating new types by inheritance in Java is the preferred way. This is true for most object-oriented languages.
Being modeled after C and C++, Java syntax will seem familiar to programmers already competent with Java's predecessors (Lemay, 1996, p10). Not all that is borrowed is necessarily good. In some cases, the designers of Java opted for familiarity rather than redesigning acknowledged overly complex mechanism (as in the case of Python). For example, the elaborate access control mechanism present in Java, inspired by C++ access control, contains five different levels of protection: public, protected, private, private protected, and default. These qualifiers effect whether your attribute is visible the same class, a subclass within the package (the way of grouping classes in Java), a subclass outside the package, or non-subclasses. These keywords also control weather an attribute is inherited by a sub-class both inside and outside the package. "All the details of field visibility in Java can become quite confusing" (Flanagan, 1995, p73). Even the creator of C++ has recognized flaws in this complex scheme. "In retrospect, I think that 'protected' is a case where 'good arguments' and fashion overcame my better judgment and my rules of thumb for accepting new features." (Stroustrup, 1995, section 13.9).
Despite not quite living up to its marketing claims, Java is an improvement over C and C++, even as a general purpose language. With a fair collection of the better aspects of it's predecessors, Java is a step in the right direction particularly for programming applets (programs that run inside of another application).
Inclusion of the Java runtime environment in the latest browsers from Netscape and Microsoft make Java applets widely accessible. With Netscape and Microsoft each supporting a Java JIT compiler, the speed of Java applets is improved to the point where performance is very close to native C.
Java is familiar. If you are already a C++ programmer, you can probably be well on your way to writing Java programs in a day or two. C programmers may take a little longer, but have the benefit of not having to unlearn the C++ object model.
Perhaps the best strength of Java seems not to be derived from superior language attributes, but the supporting infrastructure and momentum that surrounds the Java business. Java has a very polished offering for application areas dealing with the Internet. Successful marketing has made Java the rage in Internet programmability, making it an "easy sell" to upper-level management as a next-generation technology.
The Python language was created by Guido van Rossum in 1989 (Lutz, 1996, p xi). The goal was to create a language that was appealing to the UNIX/C community that enjoyed many of the features of the ABC language without some of its weaknesses. Classified as a very-high-level-language, Python possesses a simple syntax with clean and elegant semantics (Watters, 1996, p2). Python is powerful. Almost any computational concept can be expressed easily and readably in Python. Python is free and distributed mainly in source code form. Being written in C, Python is very portable. There are versions of Python for the MAC, all versions of Windows, and all but the most obscure UNIX implementations. Unlike Java, The Python implementation is conveyed with a very liberal use policy: Python may be used by anyone for any purpose so long as the Copyright notice remains in the source code. This is sharply contrasted by Java, where the source code for the language is not available for free.
While there are many features of Python that make developing large complex software easier, Python programs can be simple. Unlike Java, Python does not force the user to use object-orientation (Lutz, 1996, p53). As a result, the simplest programs are really simple. There is no need to understand inheritance, object hierarchies, or how to create new types to get started. Simple programs can be easily written in a non-object-oriented way using built in datatypes.
Python is very suitable for throw-away code; quick-and-dirty scripts that will be used only once. This is not to imply that Python is not suitable for larger endeavors. Figure 4 shows the very simple Python Hello World program.
print "Hello World!" |
C:\users\rmasse\python\HelloWorld> python helloWorld.py Hello World! |
Figure 5 shows a slightly more complicated version of Hello World using a class, default keyword parameters in the initializer, and a redefinition of the way the object represents itself as a string.
class HelloWorld: def __init__(self, hello='Hello', world=' World!') self.hello = hello self.world = world def __repr__(self): return self.hello + self.world helloWorld = HelloWorld() print helloWorld |
C:\users\rmasse\python\classHelloWorld> python classHelloWorld.py Hello World! |
The first question asked by C programmers is: "Where are the curly braces?" Python does away with curly braces by using indentation for statement grouping. While this is perhaps Python's most controversial feature (Lutz, 1996, p xii), it's difficult to deny that that this lack of syntax reduces Python's visual clutter and makes programs shorter.
Because of a clear syntactic style, Python scales very well to larger software endeavors. The Grail Internet Browser, a freely available, extensible, World Wide Web browser written completely in Python is over twenty-five thousand lines of Python. It would have been three-to-five times bigger if implemented in C++ or Java.
Python's is simple because where possible, the language provides one clear way of coding a construct. This is sharply contrasted by the original philosophy of the Perl scripting language, which provides compatibility features with many UNIX tool languages like sed and awk. Perl not only provides translators from these languages to Perl but has syntactic rules (some overlapping) to provide a subset of each environment (Wall, 1991, p377, pXIII).
Python source code is typically saved in a file with a .py extension (e.g. helloWorld.py). To run the program, one can either type: python helloWorld.py, or include a reference to the Python interpreter as the first line of the program (e.g. #! /usr/local/bin/python) as is done with UNIX shell scripts. When the script is executed from the command line, the source file is parsed into byte-code. The byte-code is then executed by the interpreter. Because Java separates this functionality into two separate programs, the Java compiler and the Java byte-code interpreter, it's clear that Java programs were never meant to be executed from source.
Both Python and Java have a mechanism for adding groupings of executable code to a program at run time by calling import. In Python, a module is a group of classes or functions that are collected in a single source file. Further grouping of modules in Python can be accomplished by placing groups of modules together in a package. Packages in Python are groups of modules collected in hierarchies of directories. In Java, every class lives in its own file. Collections of classes are known as packages. As in Python, packages in Java are often hierarchically arranged. For example the Java statement: import java.lang.String; would allow the class String from the java.lang package to be known as String alone from within your program (Flanagan, 1995, p19).
The Python import statement is defined by two steps. First find the module and initialize it if necessary. Second, define a name for the module within the local name space (scope of where the import was called). The first time the Python interpreter imports classHelloWorld it finds, parses and compiles the Python source code file classHelloWorld.py into byte-code and stores the byte-code in classHelloWorld.pyc. Subsequent programs that import classHelloWorld, do not require a recompilation of the byte-code by the interpreter unless the source file is present and has been modified.
While Python shares many features with Java such as being interpreted and having support for late binding, Python's type system is very different. Unlike Java, Python is a dynamically typed language. Type mismatch errors are not reported until your program is running. Fortunately, like Java, Python has a very nice exception mechanism which allows programmers to handle type and other runtime errors in an elegant and controlled fashion. There is a slight performance price to pay for such convenience, but after programming in Python for awhile, one finds any language with explicit typing much more verbose. For certain types of applications the overhead of dynamic typing can slow down programs. Where this is true, an extension module in C can be written to alleviate a bottleneck.
Like Java, new types can be created through inheritance with the class mechanism (see section on Object Orientation). In Python, all types are first-class objects. Integers, floats, strings, instances, functions, methods, classes, types and any other built in or user defined type may be passed as a parameter to a function (Lutz, 1996, p19).
Because all entities are first-class in Python, there is no need, as there is in Java, to consider the type of a type to determine if there are any special rules to follow.
Python may be extended with an object type written in C. These types have the advantage of executing with the speed of C and have a Python object orientation when they are manipulated. These objects are instantiated in the same way as objects that are instantiated from classes written in Python. Currently, one cannot create a new type by inheriting from an extension type created in C in out-of-the-box Python. There are currently at least two experimental mechanisms available as add-ons to Python that allow such inheritance and more seamless integration of object types implemented in C. In most cases the few simple tools (for example Modulator) that aid in migration of Python classes to extension modules written in C are all that's needed.
Python is object oriented. Unlike Java and Objective-C, Python supports multiple inheritance. Like Java and Objective-C, Python binds the names of attributes to the code that handles them at runtime. In addition, new attributes may be added to Python object classes or instances on-the-fly, simply by assigning values to them (Lutz, 1996, p48).
Classes, methods, and functions in Python are callable objects (Watters,1996, p137). A callable object can have arguments passed to it in a function call. Python supports optional arguments, keyword arguments, and generalized argument lists. These feature remove the need for the more verbose Method overloading used in C++ and Java because of their lack of support for variable arguments to functions.
The recently added mechanism for data hiding in Python is much simpler than the mechanism of Java and C++ . A name of any class attribute is made private by giving it two leading underscores (i.e. __myHiddenAttribute). Any class attribute may be hidden in this manner: class variables, instance variables, and methods.
Both Python and Java have a complete exception handling mechanism. Exceptions are very useful, particularly in late-binding languages such as Java and Python, for controlling program flow for unexpected or error conditions. You can catch exceptions thrown by the run-time environment, by an imported module, or by your own code. In Python, exceptions are typically string objects (but may be classes) and in Java they are typically derivations of the Throwable object (Lemay, 1996, p342).
In the vein of Java's strongly typed environment, it is customary to specify any exceptions your method raises where the method is defined. This practice seems verbose and extraneous because of the sometimes unpredictable nature of exceptions. Regardless, Java treats the method description as a contract so the programmer should warn the caller by specifying the exception with a throws clause. Some run-time exceptions may happen anywhere such as Java's: OutOfMemoryException. Java overcomes this by exempting all sub-classes of Thowable's Error and RuntimeException sub-classes.
public class AnIllegalClass { public String toString() { aMethodThatThrowsNewExceptions(); . . . // Returns a String object } } |
Both Java and Python have mechanism to catch groups of exceptions. Python allows the specification of an unqualified clause allowing for wildcard exception handling. Java allows any subclass of Exception to be specified in the catch clause. This allows progressions of catch clauses specify exceptions ranging from most specific to least specific. Java's exception mechanism provides a finally clause, as in Python. Finally has the side-effect of re-throwing the exception as it's last statement. Java programmers must be sure to catch new exceptions and not leak any surprises to the superclass. For example, suppose you want to override the standard method toString() from class Object (Lemay, 1996, p348) with a class outlined in figure 6. Because the super-class, in this case Object, defined the toString() method without a throws clause, every subclass must obey this restriction. Sub-classes must catch all new exceptions as illustrated in Figure 7.
public class ALegalClass { public String toString() { try { aMEthodThatThrowsNewExceptions(); } catch (IOException e) { } catch (MyFirstException m) { } . . . // Returns a String object } } |
The Python environment is less restrictive. Programmers can raise any exception regardless of whether they are in methods of a sub-class that does not throw the exception. As illustrated in figure 8, exceptions may be caught with an unqualified catch, or explicit exceptions caught by listing them.
class MyFirstClass: def exception_test(): # This try-except will catch any exception try: f = open(self.file_name, 'r') except: print 'Open error' # This try-except will only catch the IOError # exception. The dereference of self.file_name # may raise AttributeError or TypeError # Neither TypeError or AttributeError will # be caught. try: f = open(self.file_name, 'r') except IOError: print 'Error opening %s' % self.file_name |
Python's biggest strength lies in its simplicity. Python is remarkably free from many of the idiosyncrasies of traditional programming languages. At the same time, the language is very flexible and expressive. Code size reductions of 50-70% are not uncommon when comparing Python to C, C++, or Java. Much of the lack of verbosity in Python is due to a flexible dynamic type system.
Python is dynamic. With dynamic typing, dynamic binding, and dynamic calling sequences, Python extends massive flexibility in expressiveness to the programmer without the clutter.
Python has object-orientation with multiple inheritance. This allows programmers to organize large complex components in a reusable encapsulated way.
Applets are the rage in programming today's World Wide Web. They allow a Web Browser to be extended with code downloaded by an HTML page. Because of their interpreted nature, both Java and Python are very capable languages for writing applets. To support applets, a Web Browser such as Microsoft Internet Explorer, Netscape Navigator, or the Grail Browser from the Corporation for National Research Initiatives, must contain the run-time environment for the applet language it supports. The Java marketing machine has given Java a huge advantage resulting in solid Java Virtual Machines (and even JIT support for some configurations) for the two most popular commercial browsers today: Navigator and Internet Explorer. In fact, today these browsers assume all applets are written in Java. This will probably change. Support for multiple types of binary content within the same document is looming on the horizon with the ActiveX architecture from MicroSoft. For the moment, execution of Python applets is solely provided by the freely available Grail Browser which supports the execution of applets written in Python. Figure 9 shows both the Grail and Netscape browsers on their respective home pages.
Both applets in Python and applets in Java have addtional restrictions that they must follow over and above those placed on stand-alone programs.
In Java, in order to create an applet, you must extend the Applet class (Ritchey, 1995, p276). Java applets have no public instance variables. Instead, programmers must define methods to access the instance variables of an applet. All subclasses of Applet must be defined as public to insure that they can be accessed outside of the source files in which they are defined. While not a requirement for an applet, it's often a good idea to designate your Applet sub-class to implement the Runnable interface when doing long-running CPU intensive tasks such as animation. Runnable defines an interface which allows execution content in a separate thread. There are a number of support classes that allow the inclusion of audio and animation within the Java applet as well as accessing network resources via FTP or HTTP.
The Python environment for applets is much more lightweight. Other than a Python applet's entry point having to be a class, Python imposes no specific restrictions on what language constructs are used. Python comes with a number of modules that allow for convenient access to network resources as well as support for audio and animation. While Python supports threads on a number of platforms, programming in threads has not made an appearance in Python applets as of yet. This is probably due to the inherent complexity associated with threads management.
Applets can be downloaded from anywhere to run on a client system. When we run an applet, it is executing within our browser before we even know it's there. The execution environment for an applet must take steps to protect the hosting computer. While both Python and Java take steps to protect clients from malicious applets, a number of CERT advisories have been issued, the first of which was in March 1996, concerning vulnerabilities in the Java Applet Security Manager (Linthicum, 1996, p1). While most of these flaws have been discovered, fixed, and incorporated into hosting environments, we can expect continued advisories uncovering further oversights.
Java applets exercise the following policy restrictions enforced by the Java Applet Security Manager (Lemay, 1996, p131).
Python applets are executed inside of the Python Restricted Execution Environment which takes away most hooks into the host operating system. The policy currently enforced for Python applets is the same as that of Java with the exception of that currently applets are allowed to establish communication to any host. This is a known security problem in environments where trusted connections are allowed within a domain or sub-domain and disallowed from elsewhere.
As an example of the capabilities of applet programming in Python
and Java, figure 10 shows the Java "Starfield" demo
running as a Python applet within Grail. and as a Java applet
within Netscape. In either case, the "starfield" moves
points of light with varying intensities and speeds from left
to right. When watching the applet, the animation gives the impression
of peering out the side window of one's spaceship.
The corresponding source code for each applet shows the Python source, in figure 11, is about one-third the size as the Java source shown in figure 12.
from Tkinter import * import string from whrandom import random class Starfield: # Copyright (c) 1996 CNRI. def __init__(self, master, width=400, height=100, numstars=50): self.width = width self.height = height self.canvas = Canvas(master, width=width, height=height, background='black') self.canvas.pack() self.stars = [] for i in range(numstars): x = int(random()*width) y = int(random()*height) z = 1 + int(random()*10) c = 35 + z*20 color = "#%02x%02x%02x" % (c, c, c) tag = self.canvas.create_oval(x, y, x+4, y+4, fill=color) self.stars.append((tag, z, [x])) self.update() def update(self): # Hack to test if we still exist try: self.canvas['width'] except: return # tracking x this way is faster than bbox... for tag, z, xlist in self.stars: x = xlist[0] self.canvas.move(tag, z, 0) x = x + z if x > self.width: self.canvas.move(tag, -self.width, 0) x = x - self.width xlist[0] = x self.canvas.after(10, self.update) |
// Sideways star field java.applet.Applet // Arguments: NUMSTARS , X , Y // (X and Y are java.applet.Applet size) // Michael Ewert : morgansun@pinc.com import java.awt.*; import java.lang.*; class star { int x,y,z; int xa,ya; star(int i, int j, int k){ x = i; y = j; z = k; xa = i; ya = j; } } public class stars extends java.applet.Applet implements Runnable { boolean first = true; int MAXX = 400; int MAXY = 100; final int MAXZ = 200; int numStars; star starA[]; java.awt.Color colorA[] = new java.awt.Color[MAXZ]; Thread kicker = null; public void init(){ String arg = getParameter("NUMSTARS"); numStars = (arg != null) ? Integer.valueOf(arg).intValue() : 25; starA = new star[numStars]; arg = getParameter("X"); MAXX = (arg != null) ? Integer.valueOf(arg).intValue() : MAXX; arg = getParameter("Y"); MAXY = (arg != null) ? Integer.valueOf(arg).intValue() : MAXY; resize(MAXX,MAXY); for(int i = 0 ; i < numStars ; i++) { starA[i] = new star((int)(java.lang.Math.random()*MAXX), (int)(java.lang.Math.random()*MAXY), (int)(java.lang.Math.random()* (MAXZ-1))); } for(int i = 1 ; i <= MAXZ ; i++) colorA[i-1] = new Color(256-i,256-i,256-i); } public void start(){ if (kicker == null) { kicker = new Thread(this); kicker.setPriority(kicker.MIN_PRIORITY); kicker.start(); } } public void stop(){ kicker = null; } public void paint(Graphics g){ g.setColor(Color.black); g.fillRect(0,0,MAXX,MAXY); first = false; } public void update(Graphics g) { for(int i = 0 ; i < numStars ; i++){ int z = starA[i].z; starA[i].xa = starA[i].x; starA[i].ya = starA[i].y; int dx = (int)(9.*((200. - (double)z)/200.)); starA[i].x += dx+1; if(starA[i].x > 6000){ starA[i] = new star(0,(int) (java.lang.Math.random()*MAXY), (int)(java.lang.Math.random()*MAXZ)); } if(starA[i].x > MAXX) starA[i].x = 6000; } for(int i = 0 ; i < numStars ; i++){ int xa = starA[i].xa; int ya = starA[i].ya; int x = starA[i].x; int y = starA[i].y; int z = starA[i].z; g.setColor(Color.black); g.drawLine(xa,ya,xa+1,ya+1); g.drawLine(xa+1,ya,xa,ya+1); g.setColor(colorA[z]); g.drawLine(x,y,x+1,y+1); g.drawLine(x+1,y,x,y+1); g.setColor(Color.black); } if(first) paint(g); } public void run() { while(kicker != null){ repaint(); try { kicker.sleep(25); } catch (InterruptedException e) {} } } public boolean mouseDown(java.awt.Event evt, int x, int y) { first = true; repaint(); return true; } } |
The Python code in figure 11 is clearly more concise in it's representation of the algorithm than that of the Java example in figure 12, and as a result, its more readable. The conciseness is partially due to Python's use of the Tk toolkit as its GUI mechanism. Tkinter is a Python language extension module that interfaces with Tk. Since the extension module and the graphically intensive portions of Tk are written in C, its performance is adequate.
Awt provides a complete standalone GUI programming environment for Java. As with Python and Tk, much of the graphical infrastructure is already provided to the applet by the hosting browser; an existing window, an event-handling system, and a graphics context (Lemay, 1996, p130). As a result, some of awt is not needed in an applet. Applets do use awt classes to support features such as: graphics, fonts, colors, buttons, and mouse events. Awt supports some of the same high level constructs as Tk but in general requires the programmer to do more work. For example, unlike Tk, the awt developer must be aware of and manage certain events such as window exposure.
While there's nothing preventing the use of Java as a language for Common Gateway Interface (CGI) programming, no CGI specific library support appears to come with the JDK. Conversely, Python has a number of modules that make CGI programming easier.
Python's cgi module provides a number of classes that allow simple management of CGI program input and output. The FieldStorage class, for example, provides a simple interface for getting the clients uploaded information. This can be in the environment, part of a URL querystring, or on standard input. This information is returned in an object which is operated on like a standard Python dictionary.
Another problem area for CGI programmers is cleanly organizing and generating on-the-fly HTML for the CGI's output. Watters outlines a clean strategy for for self-formatting HTML objects (Watters, 1996, p224). The strategy revolves around Python's ability to add a __repr__ method, which when present, is the method that tells Python how to convert the object to a string. This conversion happens when an object is printed (i.e. print myHTMLObject).
CGI programming is an application area that illustrates how Python is more suitable for general purpose programming than Java. Scripting in the style of Java, is typically done with a separate language called JavaScript. Delivered with Netscape Navigator, JavaScript could be considered to be similar in functionality to a very small part of Python. JavaScript has a Java-like syntax and is targeted at the craft of formatting HTML. Since there is no object-orientation, Watter's self describing HTML objects are not possible in JavaScript. JavaScript, as a language, is much less capable that either Python or Java.
As a tribute to the openness of Python, the most widely used distributed object system for Python is the Inter Language Unification System (ILU) from Xerox PARC. ILU is not just for Python. The interfaces provided by ILU hide the implementation details of different languages (or a client and server of the same language), that are operating in separate address spaces (possibly on different machines), that wish to distribute and share objects.
ILU defines CORBA-like interfaces via a strongly typed specification language called ISL. Each language supported by ILU has a language specific stubber. The stubber's job is to present the interface to the language in a clear way. The python-stubber creates two abstract super-classes, one for the client and one for the server, that Python programmers derive from. Complementing Python's clean simple style, this interface hides all of the RPC ugliness inside of super-classes, that will never themselves be instantiated. This gives the programmer access to a powerful distributed object paradigm in a very clean and elegant fashion.
In addition to the ILU folks indicating work on a Java stubber, there is an effort underway called Remote Method Invocation (RMI), a number of separate efforts to add CORBA bindings to Java, and substantial other research relating to distributed objects in Java.
RMI is a Sun Microsystems technology for remote objects in Java. It includes software to provide serialization of Java objects, remote method invocation and an interface definition language, all as an add-on package to the Java Developer Kit. Python has a number of library modules that come with the distribution that provide object serialization. Combined with the ILU system, these Python tools provide roughly the same functionality as RMI, with the glaring exception that ILU integrates multiple languages.
IONA Technologies is one of at least four efforts underway to provide CORBA bindings for Java. Each of these offerings offers a slightly different interface to the language. A run-off off these technologies will likely ensue, resulting in one or two clear winners. Currently, IONA's version 2.0 of their OrbixWeb run-time for this environment is free and the developer environment costs $2,500. There is no equivalent to OrbixWeb in the Python world. The vast majority of the software for Python is freely available.
Both Python and Java appear to have a presence in the distribute object arena. While, there appears to be more activity on the Java side, ILU provides Python with solid, feature-rich remote object capability that conveys with a very liberal free-use policy that allows unlimited use, reproduction, and distribution.
Because both Python and Java provide platform-independent byte-code representations as well as restricted execution environments, an application area that is showing promise for both of these languages is the area of mobile software agents. Mobile software agents differ from applets in a subtle way. Applets are dead-on-arrival when they reach the hosting browser. They are then started from the beginning each time they are loaded. Many examples of mobile software agents, on the other hand, have the capability of directing themselves, during run-time, to move to another machine and resume execution there. Upon arriving at the new machine, the previous state of the program is reactivated and the program continues. Mobile software agents have the benefit of being able to move specific algorithmic processing closer to large amounts of data.
Both IBM (Lange, 1996) and FTP Software have published white papers and/or have a product offering based on using Java as a mobile software agent language. There is a flurry of promising research activity that uses Java (La Forge, 1996; Hohl, 1996) or Python (Hylton, 1996; Johansen, 1996) in experimental systems that involve moving programs from place to place
The application area of mobile agent computing is well represented with ongoing research and commercial projects. Both Python and Java appear to be well positioned in this area.
Both Python and Java as next-generation languages bring a lot to the table. Java's strong type system makes it familiar to those fluent in C or C++ while making it relatively easy to compile into machine code. This very typing system present in Java seems awkward and restrictive once a comfort level has been reached programming in Python.
The Java language has the privilege of being in the software spotlight at the moment. The Javasoft marketing machine has done an great job in getting the language support into all the places that count. This solidifies Java's position in the applet development area and is helping Java begin to achieve status in other network related application areas.
Both distributed object systems and efforts to provide program mobility seem alive and well for both languages. We can expect these application areas to continue to grow.
Java is still too complicated for most web-page designers with little or no formal programming experience. This has created a demand for simpler scripting tools, such as JavaScript and others. None of these simple scripting tools are worth mentioning on the same stage as these two very capable languages, because of their lack of capability and expressiveness. It is here that Python has a significant edge over Java.
Python is very simple and easy to teach to beginners, Yet Python has much of the important capabilities and power of Java. Python can be used effectively in a wider range of application areas.