|
Gates Says NC Stands For "Not Compatible". Is Java Really Suitable As A Language For Building Embedded Applications?
June 19, 1997
Java is so well-known that it has achieved nearly 100
percent brand recognition. Almost every developer of embedded systems has
considered using Java as a development language.
Is Java, in fact, suitable as a language for building
embedded applications? What criteria justify selecting Java rather than
the two most commonly used, mature and reliable high-level languages - C
and C++?
In examining those questions, a good starting point is
to look at some of the differences between Java and C and C++, focusing
on attributes that affect developers at the project level rather than at
the coding level. Of the many differences, three have the largest impact.
First, Java has no C-style independent functions. Then, too, it has no
pointers and requires a garbage collector. Third, unlike C, Java has built-in
exception handling.
The basic organizational unit of a Java program is the
class and not the function. All Java functions - known as methods, to precisely
accentuate this difference - can only exist within the context of a class.
In C, developers can create functions that call each other
and that pass data around. By contrast, in Java, the canonical way of developing
programs is by defining classes with the properties you want. Then when
your program executes, it will instantiate objects from those classes,
and those objects will communicate with each other by sending messages.
Messages in Java are just method invocations. Conceptually sending an object
a message, send (object, message_type, params) is exactly equivalent to
object.message_type (params) which invokes the method "message_type
of object," passing it arguments - "params."
By limiting the organizational units to classes, Java
enforces modularity and promotes information hiding and data abstraction,
the three most often-cited properties of well-designed and maintainable
programs.
The fact that Java has no pointers and requires a garbage
collector is another interesting aspect of the language. A pointer is the
data equivalent of a "goto"; it allows unrestricted access to
data just as a goto allows unrestricted branching. By eliminating pointers,
Java reaps benefits similar to those that arose when gotos were banished.
For instance, it is no longer possible, as it is in C, for an error in
one part of a program to change a value in some unrelated part. There simply
isn't a mechanism to reach out and touch an arbitrary piece of memory.
These kinds of errors violate even the most carefully crafted modularity.
The flip side to eliminating pointers as a language construct
is the requirement for some kind of garbage collector. Objects come into
existence programmatically, but keeping track of when an object no longer
has any references to it requires a global view, again violating the principles
of modularity. The designers of Java built a garbage collector into the
language so it could transparently make the determination of when an object
is no longer used and may then be safely disposed of.
In terms of exception handling, Java borrows and extends
C++'s concept of trying to execute a block of code, and if an exceptional
condition arises, catching that exception in a special handler. Exception
handlers, which segregate main-line code from error code, are another technique
for making sure modules (i.e., classes) really can encapsulate everything
that's needed as part of the definition of a module and exclude all else.
There are more differences between Java and C, but these
three - true object orientation, no pointers but with garbage collection,
and built-in exception handling - all enhance Java's suitability for building
large programs out of independently created pieces.
But Java doesn't stop here; it improves upon C++ as well.
Instead of augmenting the capabilities of C++ as it did to C, Java refrains
from implementing some especially troublesome features of C++. These features
were deemed by the designers of Java not to have a net benefit when the
costs of using them were weighed against the rewards.
The first of the omitted features is multiple inheritance,
which Java does not support. It's not that multiple inheritance is not
useful. But the complexity of using and implementing multiple inheritance
is high. Java would have to figure out at run-time the class to which a
multiply inherited method belonged. Multiple inheritance is possible to
implement since both Smalltalk and C++, among others, have it; but the
semantics and code needed to figure out which method has been inherited
is complex and hard to handle.
Instead Java uses interfaces, a special kind of completely
abstract classes. An interface provides only a definition of a capability;
there is no code associated with it. When a class implements one or more
interface, two things happen. First, it must provide the code to implement
the functionality defined in the interface, along with the code that the
class itself defines. Then, other classes are allowed to treat the class
as if it were of the same type as the interface. In other words, a class
can be used as if it inherited from two ancestors.
As an example, consider a class called Circle, which implements
the interface Drawable. Instances of Circle get all the members of Circle,
as well the members defined in Drawable. This means they can be viewed
both as circles and as drawables. So far so good, but the problem with
multiple inheritance occurs when there is a method of the same name in
both parent classes. C++ allows multiple implementations, with C++ deciding
which to use. Since interfaces are completely abstract, there can never
be more than one concrete implementation of a method and therefore no ambiguity.
In practice, interfaces give 80 percent of the functionality of multiple
inheritance with 20 percent of the effort.
Cost too high
The second omitted feature is template support, also known
as generics or parameterized types. Recently the Java team praised the
work on parameterized types done at the Massachusetts Institute of Technology,
but concluded - despite their evident desire to add such a capability to
Java - that the complexity was too high. Again, there's no question that
generics are useful. It's just that the added cost (complexity) outweighed
the added benefits.
The third major C++ capability that doesn't show up in
Java is the ability to overload operators. C++ allows a programmer to redefine
or extend the meaning of most operator symbols. A typical example might
be extending the addition operator, "+," to encompass complex
numbers, allowing the developer to write "A + B" where A and
B were instances of the class Complex. In theory, this added capability
is great, but in practice it makes programs hard to understand and hence
more costly to maintain. Once again, the designers of Java felt that the
benefits were not worth the drawbacks and so omitted operator overloading
from the language.
These three missing features of C++ - multiple inheritance,
template support and operator overloading - added too much complexity to
Java, especially for programmers who need to internalize their semantics
to be able to use them effectively. Java, then, is an enhanced C but
without the unneeded complexity of C++. This combination makes Java very
attractive as an embedded-system development language.
Source: Electronic Engineering Times
|