Ada 95 provides a set of packages and some special pragmas to interface with other computer languages. The three most useful pragmas are called Import, Export, and Convention:
  1. Pragma import "imports" a subprogram from another ("foreign") language into an Ada program. Use pragma import if you want to call, for example, an existing C function.
  2. Pragma export "exports" an Ada subprogram to a "foreign" language. For example, if you've written an Ada procedure and want to call it from C, use pragma export.
  3. Pragma Convention specifies that a specified type should use the storage conventions of a given "foreign" language. It is also used on subprograms if they are "callback" subprograms (described below).

Here's an example of each:

  pragma Import(C, getenv);  -- Use the C program getenv in my Ada program.
  pragma Export(COBOL, Read_Sensor); -- Provide Ada procedure "Read_Sensor"
                                     -- to the COBOL compiler.
  pragma Convention(Fortran, State_Vector) -- Read and write State_Vector
                                     -- using Fortran storage conventions
                                     -- (e.g. column-major format)

Here is the BNF for these pragmas:

  import_pragma ::= "pragma Import("
                        [ "Convention =>" ] language ","
                        [ "Entity =>" ] unit
                        [ "," [ "Link_Name =>" ] link_name ]  ");"

  export_pragma ::= "pragma Export("
                        [ "Convention =>" ] language ","
                        [ "Entity =>" ] unit 
                        [ "," [ "Link_Name =>" ] link_name ]  ");"

  convention_pragma ::= "pragma Convention("
                        [ "Convention =>" ] language ","
                        [ "Entity =>" ] unit ");"

Ada compilers always support the Convention (language) Ada, naturally enough. Your Ada compiler probably also supports the languages C, Fortran, and possibly COBOL. GNAT supports C++ as the language name CPP, and you can also interface Ada and C++ programs by having both use the C convention to send information to each other. For assembly language modules, use the name of the high level language that the module's interface mimics.

The "Link_Name" parameter often isn't necessary, but it's useful in some circumstances, for example, if you need access to an object whose name has been "mangled" in a way the Ada compiler doesn't know about or if the name is not a legal Ada identifier (such as names with leading underscores).

"Callback" subprograms are subprograms which have access (pointer) values held in some external location and are then called later using that external value. If you have an Ada subprogram that will be called this way, use pragma Convention on both the subprogram and on the access type used. This is useful, for example, in dealing with the X window graphical user interface (GUI).

If the "main" subprogram is not in Ada, there is an additional issue to consider called "elaboration". The actual main subprogram should make sure that the environment for Ada is correctly set up. This is done automatically if the main subprogram is in Ada, but if it isn't, you have to do it yourself. The Ada RM section B.1(39) suggests that compilers provide subprograms called "adainit" to start up the Ada environment and "adafinal" to clean it up after the Ada subprograms have stopped running. If you need to have a non-Ada main subprogram, check your compiler manual to see if it supports this and if there are any restrictions on what is and is not permitted. You're writing an Ada program and want to directly call an existing C function called display. Which of the following pragmas should you use? pragma Import(C, display); pragma Export(C, display); pragma Convention(C, display); Right. In addition to the pragma, you'd also need to tell Ada what display's parameters were, so the complete form would probably look something like this:

  procedure display(Value : Integer);
  pragma Import(C, display);

I say "something like this" because we haven't talked about how to send data types between languages. Let's do that now for C, a very common language; handling data types for other languages is handled similarly. No, sorry. Export would send an Ada subprogram out so that a C program could call it. Close, but not quite. Convention would make it possible to use an Ada subprogram called display out to C so that C could call it back. Try again.

Since there are many useful utilities that can be called from C it's a good idea to know how to call them from Ada. This section assumes you know the C language to some basic level; if you don't know C you can skim this section.

First, here are some general rules on how Ada and C correspond, based on the RM B.3(63):

  1. An Ada procedure corresponds to a void-returning C function.
  2. An Ada function corresponds to a non-void-returning C function.
  3. An Ada array corresponds to a C pointer to the first element.
  4. Simple scalar types (integers, floats, and access/pointer types) correspond to the obvious type in the other language.

Ada 95 provides a set of predefined packages that make it easier to interface with C. The primary package is named "Interfaces.C", which contains definitions for C types in Ada. These include C's types int, long, unsigned, and double. The C type float is called "C_float" in Ada so that it isn't confused with Ada's type Float (Ada Float and C float are probably identical, but that's not necessarily true).

The type "char_array" mimics C character arrays. Many C functions assume that character arrays are terminated with the special character "nul" (written in C as '\0'). Since Ada strings aren't normally nul-terminated, functions To_C and To_Ada convert between Ada String types and C char_array types.

There are additional packages called Interfaces.C.Strings and Interfaces.C.Pointers that provide additional types and operations on C-style strings and C pointers. In particular, package "Interfaces.C.Strings" defines the type "chars_ptr", which corresponds to the typical C type "char*" when used to point to a C string (i.e. a pointer to an array of characters). The package also defines:

  1. constant Null_Ptr, which corresponds to C's (char*)NULL,
  2. procedure Free, which corresponds to C's free(), and
  3. function Value, which takes a chars_ptr and returns a normal Ada String. This function raises an exception Dereference_Error if passed a null pointer.

Let's work through a real-life example so you can see how this really works. This example is from "package CGI", an Ada binding to the World Wide Web Common Gateway Interface (CGI). Let's say that you want to get the value of an environment variable from the Operating System, and you want to get this value via a pre-existing C function that does this. In C this function is called "getenv" and it has the following C definition (see [Kernighan and Ritchie 1988, edition 2, page 253]):

  char *getenv(char *name);

This can be pretty straightforwardly translated into Ada as:

  function getenv(Variable : chars_ptr) return chars_ptr;
  pragma Import(C, getenv);

That works, but it's inconvenient to have to keep translating values in and out of type "chars_ptr" in an Ada program. It's probably better to write a wrapper program that translates the Ada Strings to C strings (chars_ptr) and back for us. Let's define an Ada function to do that for us:

with Interfaces.C.Strings; use Interfaces.C.Strings;
-- ...

 function Get_Environment(Variable : String) return String is
 -- Return the value of the given environment variable.
 -- If there's no such environment variable, return an empty string.
 
   function getenv(Variable : chars_ptr) return chars_ptr;
   pragma Import(C, getenv);
   -- getenv is a standard C library function; see K&R 2, 1988, page 253.
   -- it returns a pointer to the first character; do NOT free its results.
 
   Variable_In_C_Format : chars_ptr := New_String(Variable);
   Result_Ptr : chars_ptr := getenv(Variable_In_C_Format);
   Result : String := Value_Without_Exception(Result_Ptr);

 begin
  Free(Variable_In_C_Format);
  return Result;
 end Get_Environment;

Notice that a lot of string manipulation is happening in the declaration section. That's an easy way to get things done, because simple Ada Strings have a fixed length once they're declared. There's a call to some function called Value_Without_Exception; that's because normally an attempt to turn a null C pointer into a string will raise an exception, and we just want to turn it into an empty string instead. That means we'll have to define such a function; here's a definition:

 function Value_Without_Exception(S : chars_ptr) return String is
 -- Translate S from a C-style char* into an Ada String.
 -- If S is Null_Ptr, return "", don't raise an exception.
 begin
   if S = Null_Ptr then return "";
    else return Value(S);
   end if;
 end Value_Without_Exception;
 pragma Inline(Value_Without_Exception);

Now we can easily get environment variables in Ada. For example, to get the value of environment variable REQUEST_METHOD, use:

  Request_Method_Text : String := Get_Environment("REQUEST_METHOD");

One thing we haven't covered are C structs. Ada records and C structs clearly correspond, but how exactly should they correspond? The Ada RM advises, but does not require, that Ada records always be passed to C as pointers to the beginning of the corresponding C struct. For those (relatively rare) cases where a C function expects to be passed a structure by value (a copy instead of the more common pointer-to-structure), you could create a new C function that converts a pointer into the actual structure and then call that new C function from Ada. However, this is simply advice, and the GNAT compiler does not follow this advice - instead, GNAT sends Ada records by value (copies). Both approaches are reasonable, but unfortunately they are different. The safest approach for passing Ada records is to always pass "access to record" values - since they are scalar, they are guaranteed to pass correctly in all Ada compilers.

The previous material should help you develop a "binding" (interface) between software components, where one component is written in Ada and another component is written in another language. Naturally, it's easier if someone else or a tool does the job for you.

Before you can evaluate what someone else has done, you need to understand the major types of bindings between an Ada program and another program. These types are called "direct" and "abstract":

  • A "direct" (also called "thin") binding provides a one-to-one mapping to Ada of whatever interface the foreign program provides. Direct bindings are easy to understand if you understand the foreign program's interface, and direct bindings for Ada are easy to create. In particular, you can use the existing documentation, which is a very important advantage for complex interfaces (like windowing systems). Unfortunately, direct bindings are often a little clumsy to work with and often don't provide the protection usually provided by Ada interfaces. Thus, it's often nicer to work with "abstract" bindings.
  • An "abstract" (also called "thick") binding provide a more abstract, Ada-like view of the foreign program. Unfortunately, while "abstract" bindings are nicer to work with, it takes work and time to create the right abstractions. Thus abstract bindings are harder to create.

Here are some other things you need to know about bindings:

  • "Direct" and "abstract" are really extremes on a continuum; there are bindings that are "mostly direct" but have been abstracted a little, and there are "abstract" bindings that have some direct one-to-one mappings.
  • The terms "thick" and "thin" have other related meanings (involving how a standard is written), which is why I've used the terms "direct" and "abstract" here.

Now that you understand these basic issues, you can go hunt for ways to make this interfacing job easier. The Ada Information Clearinghouse maintains a list of source (including Ada bindings) and a document listing existing Ada bindings for other products and standards. Their list is incomplete, but it's a good starting point, especially for common products or standards such as POSIX, X windows, Microsoft Windows, or SQL databases. HBAP also maintains a list of existing Ada bindings. If you're interfacing with a commercial product, ask the vendor to supply you with an Ada interface. You could also post a request to comp.lang.ada if you can't find what you're looking for.

Here are some commonly-requested bindings:

  1. Win32 API. This is an interface for Microsoft Windows NT, Microsoft Windows 95, and OS/2; a subset of Win32 works under Microsoft Windows 3.1.
  2. X11Ada is an Ada 95 binding to Motif and X11 developed by Intermetrics. See the general listings given earlier for other X-related bindings and information.
  3. Relational databases generally use SQL as their query language. Although you can embed SQL queries in Ada as you can with other languages, a better approach is a specialized interface language that lets you really take advantage of both languages. There's an ISO standard (ISO/IEC 12227) of such a language, named SAMeDL. The SAMeDL specification, as well as a rationale for SAMeDL and notes on applications.
  4. An Ada binding to CORBA's IDL has been developed, enabling you to request and receive requests from other programs (written in arbitrary languages and located on arbitrary machines) via CORBA. You can learn more from the Ada bindings working group, and you can download the specification from the Object Management Group (OMG).

There are also tools to automatically generate direct (thin) Ada bindings to C libraries. Here are three tools (there are others as well):

  1. C2Ada translates C into Ada; it can handle complete programs, but its primary use has been to translate C header files into Ada to create Ada bindings. C2Ada was created as a major upgrade to Cbind (below). C2Ada is easy to use to create simple bindings, but it also provides many "hooks" (in the form of a configuration file) to support control on the translation process. C2Ada is available via Intermetrics.
  2. Cbind translates C declarations and C preprocessor definitions into Ada package(s). Its strength is in ease-of-use; just type:
       "cbind file.h > file.ads".
    
    Cbind is available via Rational and Walnut Creek.

  3. CtoAda translates declarations from C to Ada. CtoAda's strength is that it provides many "hooks" to allow a programmer to control the translation. This gives more control at the expense of requiring more work by the programmer.
If you want to quickly create a binding to another language and don't mind that it might be a little clumsy to use, what kind of binding would you create? Direct ("thin") binding Abstract ("thick") binding

Sun's Java technology has become a "hot" topic. Java makes it possible for users to run programs just by browsing the World Wide Web (WWW). Using Java, WWW users can use sophisticated user interfaces and handle arbitrary data formats (the data and the program to handle the data can be sent together!). Java can also be used to distribute computer platform independent software (i.e. the same software would run on an IBM-compatible PC, Apple Macintosh, and arbitrary Unix machine).

It turns out that Java programs can be created using Ada. To understand what that means, we'll first need to define some terms.

Java Terminology

You can use Java to develop applications and applets:

  1. An application is a traditional kind of program. Users install Java applications in a manner similar to any other application, and a Java application can read files, write files, and so on. It's possible for a single Java application to run on many different computer platforms.
  2. An applet is a program that automatically starts running when a WWW user views a page containing the applet. The user does not install the applet; in fact, the user isn't even asked if he or she wants the applet to run. To keep this from becoming a security problem, applets are restricted from performing certain tasks. At this time, applets generally can't read or write to local disk files, they can't print, and they can only communicate over a network to the computer where they came from. In some cases users may grant their applets additional privileges; the key is that applets are normally restricted to keep them becoming a security problem.

The Java Technology, as developed by Sun, can be divided into four components:

  1. Specifications for the Java Virtual Machine (JVM) and class files. The JVM is an abstract computer that executes programs stored in "class" files. The JVM can be implemented on real computers in many different ways, and that's the point: as long as your computer faithfully recreates this abstract computer, it can run programs stored in class files. For example, the JVM might be implemented as an interpreter built into a web browser, or as a separate program that interprets the class files. Your computer could implement the JVM by transforming the class files into an executable program specific for that machine just before running them (this is called a "just-in-time" compiler). In fact, your computer hardware might even use JVM directly. As long as you have an implementation of the JVM, you can run Java programs, because Java programs are stored in class files. Class files are also called J-code files.
  2. The Java language. The Java language is an object-oriented computer programming language that resembles C++ and Objective-C in syntax. It resembles Ada in its emphasis on safety (for example, neither have pointers), and a strong Smalltalk influence is evident as well.
  3. A compiler that generates class files. The JVM runs class files, so you need a way to create them. Sun has developer a compiler that takes programs written in the Java language and generates Java class files. Other vendors have also developed compilers that generate class files.
  4. The Java library. The Java technology includes a set of components for simple platform-independent graphical user interface (GUI) handling as well as other useful components.

Many people use the term "Java" for each of these different components and for the technology as a whole. You'll need to determine what they mean by its context. The key point is that when people "run a Java program", they're actually running a set of class files on their version of the JVM.

An Ada compiler that accepts Ada code as its input and generates Java class files as its output makes it possible to generate Java programs using Ada. Intermetrics' Ada compiler, AppletMagic, does this, and other Ada compilers may follow.

Since programs only know about each other through their Java class files, programs written in the Java language and Ada language can freely communicate with each other. Java programs can easily call Ada programs just by looking at their class files. To permit Ada programs to call existing Java programs, Ada programs need an Ada specification. AppletMagic includes a tool called java2ada that generates Ada specifications from class files, and any other Ada-to-Java compilers would probably include similar tools.

[Relationship of Java Technology Components]

Java-Ada Correspondence

Many concepts in Ada and Java are quite close. Java's "primitive data types" generally have simple corresponding Ada types: Java "boolean" corresponds to Ada "Boolean", Java "float" to Ada "Float", Java "char" to Ada "Wide_Character", and Java "int" to Ada "Integer". All other Java data types are passed by reference, which corresponds to passing around Ada's access types. Both Ada and Java support hierarchical packages.

The Java library is a critical part of Java technology, so standard conventions are needed to define how an Ada program can call a Java library component. That way, when you read about a Java library component in a Java book, you can easily determine how to call it from Ada. The convention used by AppletMagic is that a Java class "C" in Java package "P" is translated to an Ada package named "P.C". Inside that Ada package is an Ada tagged type named C_Obj and an access type named C_Ptr. Java methods that return nothing (have "void" in front of their method name) become Ada procedures, while Java methods that return something (i.e. have some type name in front of the method name) usually become Ada functions. Java methods, unless they're defined as "static", have an implicit initial parameter identifying the object being handled; this translates to an Ada subprogram with an additional first parameter of type "access CLASS_BEING_DEFINED_Obj". All other parameters have the corresponding Ada type if they're a Java primitive type or CLASS_NAME_Ptr if they're a Java class.

For example, here's an abbreviated definition of Java class "Applet" in Java package "java.applet". Don't be confused by the use of the phrase "applet" in two different ways; Java package "java.applet" contains a number of classes, including the class "Applet". In the Java language, class Applet is defined as:

 package java.applet;
 public class Applet extends Panel {
   public void init();  // initialize the Applet.
   public boolean IsActive();
   public void resize(int width, int height);
   public Image getImage(URL url);
   public void showStatus(String msg);
 }

This is translated into the following Ada package:

 with java.awt.Panel; use java.awt.Panel;  -- Package with Parent Type.
 with java.lang.String; use java.lang.String;  -- Java Strings.
 with java.net.URL; use java.net.URL;

 package java.applet.Applet is
  type Applet_Obj is new Panel_Obj with null record;
  type Applet_Ptr is access all Applet_Obj'Class;

  procedure init(Obj : access Applet_Obj); -- initialize the Applet.
  function isActive(Obj : access Applet_Obj) return Boolean;
  procedure resize(Obj : access Applet_Obj; width : Integer; height : Integer);
  function getImage(Obj : access Applet_Obj; url : URL_Ptr) return Image_Ptr;
  procedure showStatus(Obj : access Applet_Obj; msg : String_Ptr);
 end java.applet.Applet;

Now that you know how they correspond, you can call or override the Java library routines from Ada. I suggest that you try to use the same conventions for your own packages if you're writing Java programs in Ada; while in many cases it's not necessary, it makes your program more uniform and easier to understand. The correspondence described here is from AppletMagic, but it's reasonable to expect that any other Ada compiler that generates Java would use the same conventions (these conventions were defined by the designer of Ada 95!).

More specific details of the correspondence between Java and Ada, including information on constructors, is described in a paper by Tucker Taft [1996]. Documentation on the Ada interface to the Java library is available. More Ada/Java information can be found at the Home of the Brave Ada Programmers' Java section and the SIGAda Web Working group page. As noted above, information about Intermetrics' AppletMagic is available as well. More information about Java in general can be found in the Java FAQ and Sun's Java site. A large collection of sample Java applets is available at Gamelan. Let's say that you want to write a program that is automatically run when a user views a page on the World Wide Web (WWW). Which of the following kind of program do you want to create? Application Applet Ouch, that's not it. A program that runs automatically when someone views a WWW page is called an "applet." That's correct. The next few sections will present more detail in how to write Ada applets and interface with the Java libraries. If you wish, you can skip the details on Java. Otherwise, you can go on and learn how to make Ada and Java work together. Let's see how to write one in Ada.

In this section we'll first describe event driven programming, the basic mindset of applets (and most other graphical user interface programs). We'll then examine a simple "Hello, World" applet in Ada. The section closes with a list of some other useful Applet methods.

Event Driven Programming

Most graphical user interface (GUI) programs do not run "top to bottom" in a simple linear way. Instead, most such programs are structured as components which wait for an "event" (such as a mouse button click) to occur. That event is processed, and then the component returns so that the next event can be processed. Events are queued up, so your program only needs to respond to one event at a time; later ones will not be lost. It's important that the component return, or no further event will be processed. This approach is called "event driven programming".

To create an Ada applet, we'll need to create a new type that extends the Java "Applet" class in Java package "java.applet". We can then override various methods of Applet to process events we're interested in. The default reaction to events is to return immediately (i.e. do nothing), so any events we don't override will be ignored.

A Simple Ada Applet

Here is a simple Ada applet to show the basic idea of how to implement Java applets in Ada. Below is the canonical "Hello World!" program as written by Tucker Taft; it simply displays the phrase "Hello, world!" on the screen:

with java.applet.Applet; use java.applet.Applet;
with java.awt.Graphics; use java.awt.Graphics;
package Hello is
 type Hello_Obj is new Applet_Obj with null record;
 procedure paint(Obj : access Hello_Obj; g : Graphics_Ptr);
end Hello;


with interfaces.Java; use interfaces.Java; -- for "+" on strings
package body Hello is
 procedure paint(Obj : access Hello_Obj; g : Graphics_Ptr) is
 begin
 drawString(g, +"Hello, Java world!", x => 10, y => size(Obj).height/2);
 end paint;
end Hello;

So what does this program do? Let's break it down step by step:

  1. To create an applet we must extend the tagged type "Applet_Obj" defined in the package java.applet.Applet. Since we need package java.applet.Applet, we must "with" it. Note that standard Java package names have a very simple correspondence to Ada package names.
  2. To handle graphics, we'll need package java.awt.Graphics.
  3. We'll create a new package named "Hello".
  4. We'll create a new tagged type "Hello_Obj" that extends the Java library tagged type "Applet_Obj". This new type represents our new applet, per the conventions described earlier.
  5. Almost any applet will override the default "paint" operation of Applet_Obj with something more interesting. The "paint" operation is called whenever the system determines that the graphical area controlled by the applet has been uncovered and needs to be drawn again. The parameters for the paint operation are an object representing the applet itself and an object representing the applet drawing surface (you could read the package specification of java.applet.Applet to see what other operations are defined).
  6. The package body of Hello withs "interfaces.Java", an Ada package that provides useful operations when interfacing from Ada to Java. Of particular use is a "+" prefix operation that converts an Ada string into a Java string.
  7. Paint is implemented by making a call to subprogram "drawString" in java.awt.Graphics, which draws the text into graphical viewing area "g". Note the little "+" sign used to convert an Ada String into a Java string (String_Ptr). Note that more complex Ada expressions work as well, such as the expression giving the y-coordinate for drawing.

You'll need to compile the code above, but to see it execute you also need a web page that references the applet. The web page will need to include an APPLET command. Here's a simple web page that references the applet (you can type this text into a file using a text editor and call it "hello.html"):

<HTML>
<HEAD><TITLE>Hello World</TITLE></HEAD>
<BODY>
<H1>Hello World</H1>
Below is the hello world applet.

<APPLET CODE="Hello.class" WIDTH=200 HEIGHT=100>
</APPLET>

</BODY>
</HTML>

The text beginning with "<APPLET " tells the web browser to run a Java applet. The quoted text after "CODE" indicates which program to run. The "WIDTH" and "HEIGHT" parameters specify the width and height in pixels of the graphical area the applet may use. There are other possible parameters. In particular, if the class you wish to run is not in the same directory as the web page, you need to add a "CODEBASE=" parameter that gives the directory of the class to run.

Any text between <APPLET> and </APPLET> will be displayed by web browsers that don't handle Java, which is useful so you can handle such browsers (for example, you could give them a static picture or a form instead). You can also use that area to pass parameters to the applet.

To view this applet, use a web browser that supports Java and view the web page, or run an applet viewing program (a program designed to run Java applets). If you're using a Java-capable browser, you can see the Hello applet right now. Use the "back" key on your browser to return to this page.

Other Applet Methods

A descendent of Java class Applet can override methods other than "paint" to do useful things. Here are some of those methods:

  1. init is called when the applet starts up, before any other events are processed. You can override this method to initialize some variables. Netscape also calls this method when an applet is reloaded or you return to the page containing the applet, so make sure it can handle being called multiple times.
  2. stop is called when the user is no longer looking at the page that contains the applet.
  3. start is called when a user brings their attention back to an applet, and is called after the init method.
  4. mouseDown is called whenever the mouse button is pressed. Typical uses are to highlight the item being pressed (like a button) to make it clear to the user what they're about to select.
  5. mouseUp is called whenever the mouse button is released in the applet's viewing area. In many cases you want to react to a mouse button being released (mouseUp), not when it's been pressed (mouseDown), so that users can change their mind by moving the mouse away without releasing the button.
  6. mouseDrag is called when the user moves the mouse while holding the mouse button down.
  7. keyDown is called when the user pressed a key while the applet is active.

The Java library is quite extensive; see Sun's on-line Java documentation or one of the many books on Java.

Which of the following statements is true?
  1. Most applets that use the mouse button should cause important actions to happen on mouseDown so that if the user changes his mind, he can move the mouse away.
  2. Most applets will override the "paint" operation to draw whatever it is that they want to draw.
  3. There's no way to provide alternative text or graphics for users with a Java-less web browser.
Statement 1. Statement 2. Statement 3. 1. Nope, sorry, that was tricky. The justification is good, but that justifies the operation mouseUp. The statement talks about "mouseDown". That's correct; in fact, that was the only operation the "Hello World" applet overrode. That's not true; anything between the <APPLET> and </APPLET> is displayed to the user if the web browser can't handle Java applets at all.
Let's look at how to create a slightly larger applet called "Doodle". This applet will let you do simple freehand drawing in a window - just hold down the mouse button to draw.

When a "mouseDown" occurs we'll need to remember where on the screen it occurred. When a "mouseDrag" occurs we'll need to draw a line from the last screen position to the current one. That would be enough to permit scribbling, but if the doodling area was scrolled away or a window were placed on top we'd lose the scribbles. So, let's save the starting and ending points of the lines so we can redraw it later in the "paint" method. We can store the list of starting and ending points in a Java type called a "Vector". To set up these Vectors we'll use the "init" method on the Applet. We'll also use another Java type called a Point, which simply stores a combined x and y location.

Many Java library classes have special methods called "Constructors". A Constructor creates a new instance of an object. In the Java language, any method with exactly the same method name as the class it's in is a constructor. These constructors can be called by Ada; their Ada function names are simply "new_" followed by the name of the class. For example, class Vector has a method named Vector that takes two integer parameters. Since the class and method name are identical, this must be a constructor for creating new Vectors. To use that constructor from Ada, call "new_Vector" with those two parameters. In this example, the parameters are (1) how many points the Vector should initially hold, and (2) the amount of points to increase by every time the Vector runs out of space. I've set the Vectors so they'll store 100 points, and will add space for another 100 points each time the current limit is exceeded. Unlike other non-static methods, do not add an extra parameter in front of the list - a constructor creates a new object, so there'd be nothing to pass!

Here's the source code for Doodle. You needn't study it carefully unless you plan to develop Java programs, but skim it at least to see how things are done:

If you're interested and have a Java-capable browser, you can try out the Doodle applet.

In Java package "java.awt" there is a class named "Color". The documentation for it says that one of its methods is also named "Color" and is defined as follows in the Java language:

  public Color(int r, int g, int b);

How could you call this method in Ada? Color(0, 255, 64) Color(C, 0, 255, 64) where C is something of type Color. new_Color(0, 255, 64) Nope. Remember, the class is named Color, and the method is also named Color. That means we have a Java "Constructor". No. You don't add an extra parameter at the beginning of the parameter list for a constructor. That's correct. When the class and method names are identical, you have a constructor, so you need to put the "new_" in front of the name. You can define your own constructors in Ada, but you need to use special pragmas to tell the Java system (which is very picky about the rules governing constructors).

Java also includes a construct called an "interface". Java interfaces are basically a weakened form of multiple inheritance. A Java interface is like a class you can inherit from, but all of its methods must be abstract. A class that "inherits" from an interface is said to "implement" that interface. Java classes can implement (inherit) from zero, one, or more than one interface. Thus, while Java classes can only directly inherit from one other class (as is true with Ada), they can implement zero or more interfaces.

Ada doesn't have anything that directly corresponds to a Java interface. However, to use the Java library there must be a way for an Ada program to use Java interfaces. Here's the convention you need: if you're defining an Ada type that is to implement some interface defined in the Java language as I, add to the Ada type's record a field with name "I" and type "aliased I_Obj". For example, let's say you're defining some applet My_Applet and you want it to implement a Java interface named Runnable in Java package "java.lang". You'd define your class as follows:

  with java.applet.Applet; use java.applet.Applet;
  with java.lang.Runnable; use java.lang.Runnable;

  package My_Applet is
    type My_Applet_Obj is new Applet_Obj with
      record
        Runnable : aliased Runnable_Obj;
      end record;
    type My_Applet_Ptr is access all My_Applet_Obj'Class;
  end My_Applet;

All interfaces are marked with a special pragma that tells the compiler that it's an interface and to take special actions to produce the right code.

Some operations will require you to pass the interface type instead of the regular type. For example, some Java library methods require the Java "Runnable" type (instead of, say, Java's "Applet" type). That's not a problem; instead of passing the access value A, pass such methods the value A.Runnable'Access where "Runnable" is the field representing the interface. For example, let's say you want to call the Java "Thread" constructor (called "new_Thread" in Ada). This constructor expects to be handed something of type "Runnable". You can create a new Thread by executing the following:

  My_Thread : Thread_Ptr := new_Thread(X.Runnable'Access);

You can create your own interfaces by identifying their "_Obj" type using pragma Convention with language type "Java_Interface". For example, if Concept_Obj is actually a new interface you're defining, simply say:

  pragma Convention(Java_Interface, Concept_Obj);

The "aliased" phrase above is not specific to Java, but is a standard part of Ada 95. Normally you can only obtain an access value on entire record, not of some component inside. However, sometimes you'd like to have access values that can refer to subcomponents of a record. Ada will let you do that if you identify the component as aliased. For example, the phrase "X.Runnable'Access" used above only works because Runnable is marked as "aliased".

This approach to implementing Java interfaces suggests a simple way to implement multiple inheritance in Ada, should you need to. You can use inheritance to inherit from the "most natural" class. You can then include, in your type's record, components that contain the "other" classes that you'd like to inherit from. Finally, you can redefine calls for those other classes (in the case of Java interfaces this is partly done for you). However, be very careful if you're using true multiple inheritance: many object-oriented languages (including Smalltalk and Java) don't include full multiple inheritance because it's easy to create horrifically unmaintainable structures. Use this approach only if it really appears to be the simplest and most maintainable approach. A description of various approaches for implementing multiple inheritance in Ada, should you desire it, is included in the Ada Rationale Part Two, section 4.6. You can create a class to lay out graphical components by creating a class that implements the Java interface "LayoutManager" (which is in the Java package "java.awt"). Let's say say you want to create a "Special_Layout", and you've started as follows:

  with java.lang; use java.lang; -- "Object" type is defined here.
  with java.awt.LayoutManager; use java.awt.LayoutManager;

  package Special_Layout is
    type Special_Layout_Obj is new Object with
      record
        -- SOMETHING
      end record;
    type Special_Layout_Ptr is access all Special_Layout_Obj'Class;
    -- Special_Layout methods go here.
  end Special_Layout;

What should "-- SOMETHING" be replaced with? LayoutManager : Layout_Manager_Obj; LayoutManager : Layout_Manager_Ptr; LayoutManager : aliased LayoutManager_Obj; LayoutManager : aliased Layout_Manager_Ptr; Nope. Re-read the description about "aliased". Right. Now that you know how to do this, you can use Java Interfaces whenever you need to. To be honest, the text above doesn't quite work with the current version of AppletMagic. Instead of doing:

  My_Thread : Thread_Ptr := new_Thread(X.Runnable'Access);

You need to do this:

  My_Thread : Thread_Ptr := new_Thread(Runnable_Ptr'(X.Runnable'Access));

It turns out that in the currently-available version of AppletMagic there is an ambiguity in the "new_Thread" method. The problem is that there are several "new_Thread" operations that take one parameter, and they're ambiguous enough that the Ada compiler can't determine which one to call. The "Runnable_Ptr'(" stuff tells the Ada compiler that the parameter enclosed is of type "Runnable_Ptr", which is enough to enable the code to be compiled. Close, but not quite. Look carefully at the definition of choices 3 and 4.

It makes sense to close a discussion of Ada and Java by comparing the two languages.

Ada and Java have more similarities than differences. Both the Ada language and the Java language were designed with safety in mind (both support strong typing, omit pointers, and perform many compile-time and run-time checks). Both support an object-oriented approach based on a single inheritance hierarchy. When generating class files, both Ada and Java support garbage collection, multitasking, and platform-independent graphical user interfaces (GUIs).

There are differences, of course. Here are some technical advantages of the Ada language over the Java language (SigAda has a similar list):

  1. Ada supports enumerated types.
  2. Ada supports operator overloading for infix operators (for example, you can define an infix + operation for complex numbers).
  3. Ada supports generics. There is no Java equivalent, though Java's "Interface" and its root Object class can sometimes be used to do similar things.
  4. Ada supports "in", "out", and "in out" to document the use of parameters, and these modifiers work on both tagged types and scalars.
  5. Ada is easier to read in some cases (compare "and" with "&&"; compare "for I in 1..10" with "for (i=1; i <= 10; i++)"; compare "a=b" with "a==b").
  6. Ada permits array boundaries to start with any scalar. The Java language requires array boundaries to start at 0, a common source of "one-off" errors.
  7. Ada supports numeric range checks more specific than the built-in types. This can be used to detect errors that Java doesn't.
  8. Ada supports method calls using named and unordered parameters, and supports default parameter values.
  9. Ada supports subprogram access types and nested subprograms.

Java has some technical advantages over Ada, too:

  1. Java supports "interface" types. There is no standard Ada equivalent, though Ada generics and the nesting of objects can sometimes be used to do similar things. Ada programs that generate Java code can use and define Java interfaces, using a special pragma to do so.
  2. Java permits specifications to be circular (A depends on B which depends on A), while Ada does not. There is some argument that this is a disadvantage, since circular references can indicate poorly structured systems, but in terms of ease-of-use this is an advantage.
  3. Java class definitions tend to be shorter than Ada. Here are some of the reasons for this:
    1. Ada enforces a distinction between objects and access values to objects. This causes definitions to be longer (for example, in Ada you have to define X_Obj and X_Ptr types everywhere, while all of that is not used in the Java language).
    2. Ada requires an explicit list of all classes used ("with" statements) in a class being defined. Java does not require a list of classes used; the closest Java has is its "import" statement, which is like the "use" clause in Ada.
    3. Java has an implicit "this" parameter for non-static methods; Ada requires all parameters to be explicitly listed.
    4. Java interfaces have to be handled using a somewhat clumsy Ada syntax.
  4. Java supports hierarchies of exception definitions. Java also includes definitions of exceptions that might be thrown (raised) by each method as part of the method definition.

Naturally, more than technical issues make a decision. Here are some other issues regarding the use of the Java language and Ada language for creating Java applets and applications:

  1. There are a number of tooling issues. At the time of this writing there are more Ada compilers than Java compilers, but by the time you read this there should be many compilers for both languages. Most Ada compilers generate native (high-speed) code that can take advantage of the underlying hardware, while Java compilers are just beginning to appear. However, currently only one Ada compiler can generate class files and applets, so the quantity of compilers tilts towards Java if you're solely interested in generating applets and/or class files. You'll also need to compare the tool capabilities themselves: which have better interactive development environments (IDEs)? Which have additional functionality (like user interface generators) that you'd like? Since just-in-time Java compilers that take class files can compile both Java and Ada class files, the choice of language is irrelevant for just-in-time compilers.
  2. There are large reusable component libraries for both languages, each with different focuses. Compare the relevant reusable components in the different languages for your application.
  3. There is an ISO (international) standard for Ada, while a standard for Java is probably many years away (at the time of this writing).
  4. There is a large standard test suite for Ada compilers; none yet exists for Java.
  5. There are sometimes vendor restrictions prohibiting use of the Java language for safety-critical systems; Ada is commonly used in such areas, and compilers can be bought without such prohibitions.
  6. The use of Java in real-time applications is somewhat currently a research area, while Ada is already used in such areas and has been for many years.
  7. Most Java materials and tools assume that users are using the Java language. Thus, if you're developing a Java application in Ada you'll need to learn the translation conventions (as discussed in previous sections) and be able to make such translations mentally. No such translations are needed if you're using the Java language.
Which of the following statements is true?
  1. The Java language lets you write your own infix operators, while the Ada standard supports interface types and hierarchical exceptions.
  2. A web browser that includes a just-in-time compiler for class files can't compile programs written in Ada.
  3. When generating Java class files, both Ada and Java support garbage collection and a standard graphical user interface.
Statement 1. Statement 2. Statement 3. Nope, that's reversed. The Java language, as of this writing, doesn't let you write your own infix operators. The Ada standard doesn't normally support interface types; we had to learn about a special convention and Java pragma to make them work. Not at all. A web browser with a just-in-time compiler takes the class files and compiles them. It doesn't know if you originally wrote the class files in the Java language or the Ada language, nor should it care.