Rumour has it that deep in the heart of the Pentagon is a network of computers which control the US military, the most powerful army on the planet – rather ironically they are controlled by a programming language named after a hard drinking 19th century mathematician and only daughter of Lord Byron.
As all true geeks will know the language is called Ada, after (Lady) Ada Lovelace. In her work with Charles Babbage on a steam driven calculating machine called the Difference Engine, Ada understood, perhaps before anyone else, what a computer might truly be. As such the Difference Engine is the spiritual ancestor of the modern computer.
Ada, who dined and drank with contemporaries including Charles Dickens and Michael Faraday and who was bled to death by her own physician aged just 36, has been called many things – the first computer programmer and a prophet of the computer age – but most poetically perhaps by Babbage himself as an ‘enchantress of numbers’.
The Ada programming language was originally designed by a team led by the French computer scientist Jean Ichbiah under contract to the US Department of Defense (DoD) from 1977 to 1983 to supersede the hundreds of programming languages then used by the Department.
S Tucker Taft has been heavily involved in the later Ada revisions, and still works with the language today as both a designer and user.
An industry leader in compiler construction and programming language design, he served as the lead designer of the Ada 95 programming language while employed as chief scientist at Intermetrics, Inc., and helped to direct the efforts of a Language Precision Team.
He was technical leader for development of a Static Interface Analysis Tool (SIAT) for Ada on behalf of the NASA Space Station IV&V, and a generalization of this for C++. Recently, he led the architecture and development effort of the Enterprise-Java- and XML-based ‘Mass.gov’ portal for the Commonwealth of Massachusetts.
He has published a number of papers on programming language design, and software development environments. Tucker graduated from Harvard University, where he has since taught compiler construction and programming language design. He is chairman and CTO of SofCheck.
- Tucker, how did you first become involved with Ada?
- After college, I worked for Harvard from 1975-1979 as the first full-time systems programmer for a Unix system outside of Bell Laboratories. During that period I hung around the computer science department a fair amount, and began to become aware of the DoD-1 language competition. Tom Cheatham, a professor at Harvard and a legend in the programming languages world, was somewhat involved with the process, and had copies of the language proposals from the four finalists, which were identified by the colors Red, Green, Blue, and Yellow. I was already fascinated by programming language design at that point, and delved into all four language proposals, ending up with all kinds of strong opinions about what was good and bad in the various designs. In 1980 I went to work for Intermetrics, which it turned out had been the authors of the Red language, which ultimately came in second. The Green language was designed by a team led by Jean Ichbiah and was the winner. By that time Intermetrics had moved on to competing for the Air Force Ada Integrated Environment (AIE), even though the language standard hadn’t quite stabilized into what became known as Ada 83.
- I ended up leading the effort to design the program support environment part, as opposed to the compiler per-se. The competition involved a 6-month design phase for the three competitors, and then an exhausting 12-month evaluation phase, after which Intermetrics finally won.
- I pretty much lived and breathed Ada and Ada compilers for the next 20 years, with an occasional break to work on things like SQL for Ada, on KIT/KITIA (a standardized interface to programming support environments), and on Mass.Gov – an XML-based web site for the Commonwealth of Massachusetts. In the early years I kept griping about Ada, since we not only had to build a compiler for Ada, but also in Ada. I even managed to get one of my proposed solutions to what I saw as one of Ada’s initial problems into the Ada 83 standard which was the proposal allowed for the full type designated by a private pointer type to be postponed into the package body.
- The highlight of my time at Intermetrics was certainly the Ada 95 language design process. Unlike the first time around, Intermetrics came out on top in the competition to develop the first major revision of Ada, at that time known as Ada 9X (based on the presumption it would see the light of day some time in the 90’s). I was the technical lead for the team to develop the detailed design for Ada 9X, and it was a fabulous project, thanks in large part to the DoD person running it (Chris Anderson) and the great support provided by the world-wide Ada community.
- What are the main differences between the original Ada and the 95 revision? How was Object-Oriented Programming provided for in Ada 95?
- My ‘elevator speech’ during the Ada 9X design process emphasized three major features: hierarchical program libraries, protected objects, and object-oriented programming. Hierarchical program libraries enhanced the namespace for Ada library units into a hierarchy, with information hiding based on the hierarchy of library units (unlike, for example, in Java, where there is no special visibility provided to a Java subpackage into the declarations of the enclosing Java package).
- Protected objects enhanced the real-time multi-tasking model of Ada with a data-oriented synchronization mechanism, to augment the purely rendezvous-based synchronization provided by Ada 83. From the point of view of Ada’s most important real-time embedded systems market, this was probably the most valuable new feature. It also remains what I would humbly say is the best synchronization building block available in any mainstream language today, providing a unique combination of flexibility and safety.
- Object-oriented programming in Ada 95 was provided by generalizing an existing feature of Ada 83 called “derived types,” where a new type could be created from a preexisting type. In Ada 83, the two types were limited to being structurally identical, with the only difference being potentially the definition of the “primitive” operations. In Ada 95, we added the ability to extend the pre-existing type with additional components. In addition, we provided a run-time “tag” so that a single algorithm could manipulate in a common way all types extended from the same root type, while not losing track of the original identity of the type. The tag is also used to provide the equivalent of what C++ calls virtual function calls, where a call on a primitive operation of the type automatically dispatches at run-time to the appropriate implementation of the operation, depending on the value of the tag (which is typically a pointer to a table of subprogram pointers).
- What was the reasoning behind the revision in 1995?
- All ISO standard languages go through a regular revision cycle, approximately every five to ten years. By the late 80’s, it was clear that it was time to start thinking about a revision of Ada. The DoD went about things in its usual systematic style, and convened a “Requirements” team to collect a set of revision requirements from the community and refine them into a requirements document to drive the rest of the process. They then initiated a competition for the “Mapping/Revision” team to “map” the requirements into language revision proposals. As mentioned above, Intermetrics won that competition. In addition, there were three User/Interface teams that actually implemented the proposals as they came along, and a Language Precision team that worried about analyzing the formal semantics for the various proposals. Finally there were the Distinguished Reviewers, who formed the DoD’s expert panel to evaluate the proposals. Over time this group evolved into an official ISO working group (WG9), with formal country-delegation-based voting procedures to be used when there was some issue that could not be resolved by consensus.
- Object-oriented programming was growing in popularity in the mid-1990s though it was not still fully trusted by much of the software development community. How did you convince people that OOP and the 95 revision was the future?
- You are right that many folks, particularly in the real-time community, viewed object-oriented programming with suspicion. In part because of that, one of our goals was to ensure that there was no “distributed overhead” from adding object-oriented features to the language. That is, if a given programmer used Ada 95, but didn’t use any object-oriented features, they paid no overhead just because the OO features existed in the language.
- We took this goal of minimizing distributed overhead somewhat further, and made sure that even when you used object-oriented features, the amount of dynamic binding of calls was controlled, so that static binding was used by default unless the programmer made a specific effort to use a dynamically dispatched call. This involved distinguishing between a single “specific” type, and the set of types rooted at a point in the type hierarchy (dubbed a ‘class-wide’ type, denoted by T’Class). Other languages addressed this similar situation somewhat differently. In C++, dynamic binding is used by default with pointers and references, while static binding is used with objects and in the presence of the “::” operation. In Java, static binding for calls on virtual methods is not really possible; essentially all such calls are dynamically bound, the one exception being a call on superclass methods.
- We had attended an interesting OOPSLA conference during this design period, where a panel of early adopters of object-oriented programming were bemoaning the unpleasant coupling that was occurring between standard OO libraries (e.g. Microsoft Foundation Classes) and extenders of those base classes. This coupling was due to the pervasive use of dynamic binding, meaning that when a new version of an OO library was released, code that extended the base classes often began behaving mysteriously due to different uses of dynamic binding in code buried within the base classes. The Ada 95 approach didn’t suffer from this coupling, because dynamic binding was not the default. The painful experiences described by these developers made us believe we had made the right choice as far as dynamic binding. Since that time this advantage has also been seen in the testing regime, because every dynamically-bound call represents a significantly increased testing burden for developers needing to achieve near full path coverage.
- As you would expect the Ada 2005 is far more rounded than the 1995 revision. How was the 2005 design process different from the Ada 95 process?
- The Ada 2005 process was not funded by any government agency, though some funding for the project editor was provided by the Ada Resource Association and by AdaEurope. This meant there was no full-time design team, and most of the work was done by volunteers largely on their own time. Nevertheless, the process did not devolve into the classic “committee-design” process, largely because all members of the team had a long history with the language and were all very much committed to preserving the strengths of Ada, such as readability, reliability, real-time control, absence of distributed overhead, etc., while still being willing to consider language changes that clearly served programmer’s needs.
- The Ada 2005 process was also helped by a growing consensus in the language-design “world” that providing multiple inheritance of interfaces only was a nice compromise between the inflexibility of pure single inheritance, and the complexity of full multiple inheritance of implementations. We therefore embraced early on the notion of interfaces, and integrated them not only into the existing object-oriented features of Ada 95, but also into the multi-tasking features of Ada 95 such as protected types and task types. I think all members of the Ada 2005 “team” are quite proud of the work we accomplished in integrating inheritance and synchronization, which has been recognized in the past as a very tough language-design challenge.
- We also incorporated a number of innovative real-time features, particularly support for the scheduling regime known as EDF (earliest deadline first).
- Ada was used for a number of US Defence projects including the Apache helicopter and the Lockheed C-130J The Ada compilers would have been immature at this time, so what were the big challenges?
- Early adopters tended to use the “Pascal subset” of Ada, avoiding things like tasking and generics which were known to be flaky or inefficient in the early compilers. It wasn’t really until the release of the Digital Equipment Corporation Ada compiler for the VAX that Ada compilers really reached the “industrial-strength” level. With the DEC VAX Ada compiler showing the way, all of the other compilers began to get their act together, and ultimately most Ada compilers achieved parity in performance with the compilers of other languages.
- Would you agree that with C#, it feels like we’re getting back to having grown-up design languages, rather than languages just emerging from short-term necessity? Why did it take so long for this to happen do you think?
- I agree that both C# and Java show attention to certain language design issues that seemed to have been missing for some other language design efforts during the 80’s and 90’s. Basically, the goal of making a language fundamentally safe while still making it powerful was not a big part of the C, C++, or Fortran language-design efforts. That is slowly changing, even for C, in part because the reason given to sacrifice safety was often related to performance, and hardware advances have thankfully helped to alleviate (though of course not eliminate) that concern. Also, the increase in concern for security of web-based applications written in languages like C and C++ has forced these language communities to focus energies on mitigating some of their more blatant vulnerabilities.
- On the other hand, some of the scripting language designs seem to be steps backward. Because of their typically interpreted implementation, they can provide things like array bound checks, etc. But some of them are notoriously bad in terms of security, such as providing easy targets for SQL injection or cross-site scripting.
- I would also say that in some cases, a concern for safety and security has not been accompanied by a concern for correctness. For example, in the initial design of Java there were no enumeration types. It is true that enumeration types don’t directly address a safety or security concern, but they definitely enable the programmer to avoid a number of silly mistakes, and make it more likely that a program is ultimately correct once it compiles and runs to completion. Ultimately enumeration types were added to Java, and that was very good to see.
- A little while ago I interviewed Bjarne Stroustrup and he said Kierkegaard was an influence on his conception of C with classes and later the C++ language. Has any philosopher influenced your work?
- More a philosophy than a philosopher, I suppose. My philosophy is that the language in which something is expressed can have a significant, even profound, effect on the clarity with which it is expressed and then perceived and understood. Programming languages should more than anything strive to be clear and communicative, since if human readers can’t understand programs, how can we hope to determine whether they are right or wrong. The programming language should enable the programmer to express their intent explicitly and clearly, rather than forcing the programmer to obscure their intent by having to dramatically transform it into the low-level or obscure symbols or grammar of the language.
- How do you see the future for procedural programming languages?
- It is good to see more attention being focused on the safety and security of languages. As I mentioned above, that hasn’t always been accompanied by a corresponding concern for correctness, but that also seems to be changing. More languages or IDEs are supporting the notion of annotations such as preconditions and post-conditions, whose primary purpose is to promote clarity and correctness. My hope is that this shift will continue, with an accompanying increase in automatic verification capabilities for programs that make use of such annotations.
- The other major thrust has to do with multi-threaded applications, to take advantage of the growing predominance of multicore systems. Ada has supported multithreading since its inception, but few other languages have provided the kind of flexible and safe capabilities provided by Ada. Java included multithreading from the beginning, but the Java primitives are woefully unsafe when it comes to preventing race conditions, priority inversions, etc., meaning that writing safe and efficient multithreaded applications in Java is not as straightforward as it should be. My own belief is that we may need to start from scratch with a language that is parallel by default, where programmers have to work to turn off the inherent parallelism.
- One of my pet projects is designing such an inherently parallel language, tentatively dubbed ParaSail, for Parallel Specification and Implementation Language. It will attempt to incorporate the lessons learned from a career spent working on Ada, while embracing annotations and implicit parallelism in all their glory, to support the development of efficient, safe, correct, and highly scalable parallel systems. Stay tuned…