home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-04-11 | 111.2 KB | 2,780 lines |
- Archive-name: computer-lang/Ada/programming/part1
- Comp-lang-ada-archive-name: programming/part1
- Posting-Frequency: monthly
- Last-modified: 7 February 1995
- Last-posted: 19 January 1995
-
- Ada Programmer's
- Frequently Asked Questions (FAQ)
-
- IMPORTANT NOTE: No FAQ can substitute for real teaching and
- documentation. There is an annotated list of Ada books in the
- companion comp.lang.ada FAQ.
-
- This is part 1 of a 3-part posting.
- Part 2 begins with question 5.6.
- Part 3 begins with question 9.4.
- They should be the next postings in this thread.
-
-
- Introduction
-
- Ada is an advanced, modern programming language, designed and
- standardized to support and strongly encourage widely recognized
- software engineering principles: reliability, portability, modularity,
- reusability, programming as a human activity, efficiency,
- maintainability, information hiding, abstract data types, genericity,
- concurrent programming, object-oriented programming, etc.
-
- All Ada compilers must pass a validation test. Ada is not a superset
- or extension of any other language. Ada does not allow the dangerous
- practices or effects of old languages, although it does provide
- standardized mechanisms to interface with other languages such as
- Fortran, Cobol, and C.
-
- Ada is recognized as an excellent vehicle for education in programming
- and software engineering, including for a first programming course.
-
- Ada is defined by an international standard (the language reference
- manual, or LRM), which has been revised in 1995. Ada is taught and
- used all around the world (not just in the USA). Ada is used in a very
- wide range of applications: banking, medical devices,
- telecommunications, air traffic control, airplanes, railroad
- signalling, satellites, rockets, etc.
-
- The latest version of this FAQ is always accessible through WWW as
- http://lglwww.epfl.ch/Ada/FAQ/programming.html
-
- Maintenance
-
- This FAQ is maintained on an individual volunteer basis, by Magnus
- Kempe (Magnus.Kempe@di.epfl.ch). [Note: This is done as a hobby, not
- in my capacity as an employee at the Swiss Federal Institute of
- Technology. --MK]
-
- The coding style used in most of the example Ada code is my own, and
- you'll have to live with it (you may want to adopt it :-).
-
-
- _________________________________________________________________
-
- Opinions (if any) expressed are those of the submitters and/or
- maintainer.
- _________________________________________________________________
-
-
- Table of Contents:
-
-
- * 1: Recent changes to the FAQ
-
- * 2: Information about this document
-
- * 3: Elementary Questions
- + 3.1: How do I make operations directly visible without
- "use"ing a package?
- + 3.2: How do I assign to an array of length 1?
- + 3.3: How do I create a C-style nul-terminated string?
- + 3.4: How can I create an array of strings of various length?
- + 3.5: I know an exception is raised, but my program quits with
- no warning. Why?
- + 3.6: I have only one task in my program, but it doesn't seem
- to run. Why?
- + 3.7: How do I increase the stack size for a task?
- + 3.8: What's the difference between a type conversion and a
- qualifier?
- + 3.9: How do I avoid the potential space in front of
- Integer'Image?
- + 3.10: Why is an exception raised when giving a default
- discriminant?
- + 3.11: When I want an Integer type, what's wrong with just
- using the predefined type Integer or Long_Integer? Why would
- I ever want to declare new Integer types?
- + 3.12: Since I can always declare my own portable integer
- types, why would I ever want to use the predefined type
- Integer?
- + 3.13: I am learning Ada. Can I experiment with a game
- program?
-
-
- * 4: Advantages of Ada
- + 4.1: Why use Ada?
- + 4.2: Ada seems large and complex, why is it this way?
-
-
- * 5: Object-Oriented Programming with Ada
- + 5.1: Why does Ada have "tagged types" instead of classes?
- + 5.2: Variant records seem like a dead feature now? When
- should I use them instead of tagged types?
- + 5.3: What is meant by "interface inheritance" and how does
- Ada support it?
- + 5.4: How do you do multiple inheritance in Ada 9X?
- + 5.5: Why are Controlled types so, well, strange?
- + 5.6: What do "covariance" and "contravariance" mean, and does
- Ada support either or both?
- + 5.7: What is meant by upcasting/expanding and
- downcasting/narrowing?
- + 5.8: How does Ada do "narrowing"?
-
-
- * 6: Ada Numerics
- + 6.1: Where can I find anonymous ftp sites for Ada math
- packages? In particular where are the random number
- generators?
- + 6.2: How can I write portable code in Ada 83 using predefined
- types like Float and Long_Float? Likewise, how can I write
- portable code that uses Math functions like Sin and Log that
- are defined for Float and Long_Float?
- + 6.3: Where's a good place to start learning the Ada 95
- numerics model?
- + 6.4: How do I get Real valued and Complex valued math
- functions in Ada 95?
- + 6.5: What libraries or public algorithms exist for Ada?
-
-
- * 7: Efficiency of Ada Constructs
- + 7.1: How much extra overhead do generics have?
-
-
- * 8: Advanced Programming Techniques with Ada
- + 8.1: Does Ada have automatic constructors and destructors?
- + 8.2: How can I redefine assignment operations?
- + 8.3: Should I stick to a one package, one type approach while
- writing Ada software?
- + 8.4: What is the "Beaujolais Effect"?
- + 8.5: What about the "Ripple Effect"?
-
-
- * 9: Ada and Other Programming Languages
- + 9.1: Where can I find programs that will translate from [some
- language] to Ada?
- + 9.2: How can I convert Ada 83 sources to Ada 9X?
- + 9.3: I hear that Ada is slower than Fortran or C, is that
- true?
- + 9.4: Isn't Ada less "elegant" than Eiffel?
- + 9.5: Are there any papers detailing the differences between
- Ada and C++?
- + 9.6: I keep hearing that Ada is a "strongly typed language",
- but it seems different from what's meant in C++. Are they
- different?
- + 9.7: I'm told Ada does all sorts of static type checking, but
- can't you get the same effect using a tool like "lint" with
- C?
- + 9.8: Does Ada have something like the Standard Template
- Library (STL) in C++, or like the components one finds in
- Smalltalk environments?
- + 9.9: Where can I find the equivalent of "printf" in Ada?
-
-
- * 10: Interfacing with Ada
- + 10.1: I am writing software that used the Distributed
- Interactive Simulation (DIS) interface, does an interface
- exist in Ada?
- + 10.2: Is there any support for Common Object Request Broker
- Architecture (CORBA) for Ada 9X?
-
-
- * 11: Finding Additional Information
- + 11.1: Where can I find Ada books?
- + 11.2: Are there other Ada-related FAQs?
- + 11.3: What is the "Ada WWW Server"?
-
-
- * 12: Pretty-printing Ada Source Code
- + 12.1: Is there software that generates a pretty PostScript
- file from Ada source code?
- + 12.2: I use vgrind to do "pretty printing" of my source. Is
- there a vgrind definition for Ada?
- + 12.3: How about a source code reformatter?
-
-
- * 13: Common Confusions
- + 13.1: Wasn't Ada designed by some committee? What kind of a
- language could you possibly get from a committee?
- + 13.2: I've heard the DoD is dropping all Military standards
- to reduce costs, doesn't that mean the mandate to use Ada
- goes away too?
-
-
- * 14: Credits
-
- * 15: Copying this FAQ
-
-
- _________________________________________________________________
-
-
- 1: Recent changes to the FAQ
-
-
- * 950207: revised introduction.
- * 950202: updated equivalents of C++ STL and Smalltalk library.
- * 950126: advantages of code sharing for generics, Pascal to Ada
- tool.
- * 950125: why define new integer types, and why use the predefined
- Integer type, submitted by Jonathan Parker.
- * 950124: approved for posting in *.answers.
- * 950116: converting Ada 83 code to Ada 9X.
- * 950109: more on DIS.
- * 950106: lengthy code sections extracted and put on FTP server.
- * 950105: printf solution; update on exception traces and vgrind.
- * 950104: links from TOC to all questions.
- * 941222: pretty-printing solutions.
- * 941220: numbered all questions; various updates.
- * 941215: one-element aggregates.
- * 941212: additional elementary questions, submitted by Paul Pukite.
- * 941212: examining the so-called "elegance" of Eiffel (vs. Ada).
- * 941212: integrated "Ada Numerics" section contributed by Jonathan
- Parker.
- * 941208: added "default discriminant" and "Beaujolais effect."
- * December 1994: more re-organization, HTML'ized.
- * October 1994: FAQ format by Magnus Kempe.
- * September 1994: first draft by Dave Weller.
-
-
- What's important and missing:
- * everything, life, and 42
-
-
- _________________________________________________________________
-
-
- 2: Information about this document
-
- This file is posted monthly to comp.lang.ada, comp.answers, and
- news.answers.
-
- This document has a home on the Ada WWW Server, in hypertext format,
- URL http://lglwww.epfl.ch/Ada/FAQ/programming.html
- The text-only version is also available in directory
- ftp://lglftp.epfl.ch/pub/Ada/FAQ
-
- It is available--as posted in *.answers--on rtfm.mit.edu, which
- archives all FAQ files posted to *.answers; see
- ftp://rtfm.mit.edu/pub/usenet-by-group/news.answers/computer-lang/Ada
-
- Magnus Kempe maintains this document; it's not a job, it's a hobby.
- Feedback (corrections, suggestions, ideas) about it is to be sent via
- e-mail to magnus.kempe@di.epfl.ch . Thanks.
-
- In all cases, the most up-to-date version of the FAQ is the version
- maintained on the Ada WWW Server. Please excuse any formatting
- inconsistencies in the posted version of this document, as it is
- automatically generated from the on-line version.
-
- _________________________________________________________________
-
-
- 3: Elementary Questions
-
-
- 3.1: How do I make operations directly visible without "use"ing the package?
-
- In Ada 83, you can rename the operations in your scope.
-
- -- Say you have an integer type called Int in package Types
- function "<" (Left, Right : Types.Int)
- return Boolean
- renames Types."<";
- -- Make sure the profiles of the first and last "<" match!
-
-
- For operators, Ada 95 introduces the "use type" clause:
-
- use type Types.Int; -- makes operators directly visible
-
-
- 3.2: How do I assign to an array of length 1?
-
- Because of ambiguity of parentheses, named notation must be used for
- one-element aggregates (or, under a different angle: a positional
- aggregate must have more than one component).
-
- See [RM9X 4.3.3(7)] as well as the syntax rule of
- positional_array_aggregate in [RM9X 4.3.3]; historians see [RM83
- 4.3(4)].
-
- declare
- Array_of_One : array (1..1) of Float;
- begin
- -- Array_of_One := (10.0); -- Won't work, parsed as an expression
- -- within parentheses
-
- Array_of_One := (1 => 10.0); -- No ambiguity here
- end;
-
-
- You can't write a one-element positional aggregate in Ada. Nor a
- zero-element aggregate. The reason for this restriction is that it
- would be difficult for compilers to determine whether:
-
- ( exp )
-
- is a parenthesized expression of some type, or an aggregate of an
- array type. If Ada had used some other notation for aggregates (say,
- "[...]"), then this problem would not exist.
-
- Apparently the original requirements for Ada forbade using certain
- ASCII characters, like '[' and ']', because those characters were not
- available on all hardware. Also, certain characters are used for
- different purposes and glyphs in countries that need additional
- letters not present in ASCII.
-
-
- 3.3: How do I create a C-style nul-terminated string?
-
- In a declaration block, append an ASCII.NUL to create a constant Ada
- string.
-
- declare
- Str_Nul : constant String := Str & ASCII.NUL;
- begin
- Call_Requiring_C_String (Str_Nul (Str_Nul'First)'Address);
- end;
-
- -- or --
-
- function Nul_Terminate (Str : String)
- return String is
- Str_Nul : constant String := Str & ASCII.NUL;
- begin
- return Str_Nul;
- end Nul_Terminate;
-
-
- 3.4: How can I create an array of strings of various length?
-
- In Ada 83, you have to use string access types and "new" to get
- "ragged" arrays:
-
- type String_Access is
- access String;
-
- Strings : constant array (Positive range 1..3) of String_Access
- := ( 1 => new String'("One"),
- 2 => new String'("Two"),
- 3 => new String'("Three")
- );
-
-
- In Ada 95, the process is simplified by using aliased constants:
-
- type String_Access is
- access constant String;
-
- One : aliased constant String := "One";
- Two : aliased constant String := "Two";
- Three : aliased constant String := "Three";
-
- Strings : constant array (Positive range <>) of String_Access
- := ( 1 => One'Access,
- 2 => Two'Access,
- 3 => Three'Access
- );
-
-
- 3.5: I know an exception is raised, but my program quits with no warning. Why?
-
-
- On some Ada compilers, you have to manually "with" Text_IO before
- exception information is diplayed to the terminal.
-
- On other Ada compilers, you must set an environment variable flag in
- order to cause the exception information trace to be displayed.
-
-
- 3.6: I have only one task in my program, but it doesn't seem to run. Why?
-
- In Ada, the main procedure is automatically designated as a task.
- This task may be running forever, thus starving your other task(s),
- because pre-emptive scheduling is not required.
-
- If your Ada run-time exhibits that --pretty rare-- behavior, one
- solution is to explicitly put the main task to sleep within a loop
- construct, as in:
-
- procedure Main is
- task Test;
- task body Test is
- begin
- loop
- delay 1.0;
- Text_IO.Put_Line ("Test");
- end loop;
- end Test;
- begin
- loop
- delay 20.0;
- Text_IO.Put_Line ("Sleeping then writing");
- end loop;
- end Main;
-
-
- 3.7: How do I increase the stack size for a task?
-
- Define the task as a "task type" and then use a pragma representation
- clause.
-
- task type A_Task_Type;
- for A_Task_Type'STORAGE_SIZE use 10_000;
- -- 10K bytes allocated to instances of A_Task_Type
- A_Task : A_Task_Type;
-
-
- 3.8: What's the difference between a type conversion and a qualifier?
-
- Use a qualifier (tick) to tell the compiler what type you want; this
- incurs no run-time penalty. In other words, a qualifier "hints" the
- type.
-
- A : Integer := Integer'(1); -- same as := 1
- B : Integer := Integer (1); -- this is a conversion
-
-
- 3.9: How do I avoid the potential space in front of Integer'Image?
-
- Code a function that accepts a string and strips the leading blank.
-
- function Strip_Leading_Blank (Str : String)
- return String is
- begin -- Strip_Leading_Blank
- if Str (Str'First) = ' ' then
- return Str (1+Str'First .. Str'Last);
- else
- return Str;
- end if;
- end Strip_Leading_Blank;
-
- ...
-
- function My_Image (I : Integer)
- return String is
- begin -- My_Image
- return Strip_Leading_Blank (Integer'Image (I));
- end My_Image;
-
- ... My_Image (12) = "12" ...
-
-
- 3.10: Why is an exception raised when giving a default discriminant?
-
- Let's assume you would like to model varying-length strings:
-
- type V_String (Size : Natural := 0) is
- record
- S : String (1 .. Size);
- end record;
-
-
- (from Robert Dewar)
-
- When you give a default discriminant, then one method (I actually
- think it is the preferred method) of implementation is to allocate the
- maximum possible length. Since your discriminant is of type Natural,
- this clearly won't work!
-
- GNAT may compile it, but it won't run it, and indeed I consider it a
- GNAT bug (on the todo list) that no warning is issued at compile time
- for this misuse.
-
- Some compilers, notably Alsys and RR, have at least partially "solved"
- this problem by introducing hidden pointers, but this to me is an
- undesirable implementation choice.
-
- First, it means there is hidden heap activity, which seems
- undesirable. In a language where pointers are explicit, it is
- generally a good idea if allocation is also explicit, and certainly
- for real-time work, hidden anything is worrisome.
-
- Second, it is not easy to do uniformly. Alsys ends up introducing
- arbitrary restrictions on the composition of such types (try making an
- array of them), and RR introduces non-contiguous representations,
- which are legal but troublesome.
-
- To "solve" the problem yourself, just declare a reasonable maximum
- length, and use a subtype representing this length as the subtype of
- the discriminant:
-
- Max_Length : constant := 200;
-
- subtype Index is
- Natural range 0 .. Max_Length;
-
- type V_String (Size : Index := 0) is
- record
- S : String (1 .. Size);
- end record;
-
-
- 3.11: When I want an Integer type, what's wrong with just using the predefined
- type Integer or Long_Integer? Why would I ever want to declare new Integer
- types?
-
- If you declare 2 distinct integer types, for example,
-
- type Data_Index is range 1..100;
- type Time_Series_Index is range 0..2**15-1;
-
-
- then objects of type Data_Index can't be assigned (directly) to
- variables of type Time_Series_Index, and vice-versa. Likewise,
- variables of these 2 types can't be mixed in arithmetical expressions
- (without explicit type conversions). This may seem like a source of
- endless irritation, but on the contrary, good progammers use it to
- improve the clarity of their code, to make it more robust, and more
- portable. The first 2 examples discuss this. The third example
- discusses the declaration of machine-portable 32-bit integers.
- Declaring objects of type Integer can be highly non-portable, and of
- course type Long_Integer may not exist on some compilers.
-
- Example 1.
-
- Suppose you declare arrays using the above indices:
-
- type Time_Series is array (Time_Series_Index) of Float;
- type Y_Axis_Data is array (Data_Index) of Float;
-
- Measurement : Time_Series;
-
-
- Now if you mistakenly try to iterate over one array with the index of
- the other, the compiler can catch the error at compile time:
-
- for I in Data_Index loop
- Sum := Sum + Measurement(I); -- compilation error
- end loop;
-
-
- Example 2.
-
- This is lifted from Tucker Taft's brief introduction to Ada 95 in the
- contributed papers section of the Ada World Wide Web homepage. Here
- Tucker uses the Ada 95 unsigned integers, called modular types, in the
- implementation of a protected type, which defines a disk control unit.
- Modular types are integer types with "and", "or" and "xor" defined, so
- systems programmers are likely to use them as bit masks. Just as the
- array indices of the 2 arrays defined above are never meant to be
- mixed, the modular integer types used to implement the disk control
- unit are never meant to be mixed. To make sure the compiler enforces
- this, they are declared as distinct types:
-
- type Flags is mod 2**4; -- a 4-bit flags field
- type Control is mod 2**4; -- A 4-bit control field
-
- Status_Mask : constant Flags := 2#1001#; -- Set first and last bits.
- Status_Ready : constant Flags := 2#1000#; -- Status = Ready
-
- Start_Xfr : constant Control := 2#0001#; -- Initiate xfr command
-
-
- Now if someone attempts to apply a Flag variable where a Control
- variable should be used (or vice-versa) the compiler will catch the
- error. This is especially important when the code is maintained by
- programmers who did not write it.
-
- Remarks on Examples 1 and 2.
-
- 1. Notice that in both examples the programmer was able to state his
- intentions rather forcefully in the code - intentions that otherwise
- might have been expressed much less forcefully in comment statements.
- Because of Ada's strong typing model, the compiler was able to catch
- errors at compile-time when the programmer's intentions were violated.
-
-
- 2. Notice also that the Integer declarations in the 2 examples are
- machine portable, unlike Integer and Long_Integer. A compiler will
- typically map these integer types onto the most efficient base type
- that is available on the target machine.
-
- Example 3.
-
- Although the examples given above are good ones, it is not necessarily
- a common practice to define a large number of distinct integer types.
- In many cases it is appropriate to use (say) a 32-bit integer (or a
- small number of such types) and declare appropriate subtypes of it
- (them). To declare a portable 32-bit integer (or more accurately, the
- most efficient integer that is at least 32-bits):
-
- type Int_tmp is range -2**31+1 .. 2**31-1;
- type Integer_32 is range Int_tmp'Base'First..Int_tmp'Base'Last;
-
-
- A compiler may reject this declaration if no suitable base type is
- available, but this is rare. What happens is this: in order to
- implement Int_tmp, the compiler chooses as the base type of Int_tmp an
- integer type that is available on the target machine. This base type
- is usually the most efficient integer that accomodates the range of
- Int_tmp, which in turn is usually the machine's 32-bit integer. (It
- might even be a 64-bit integer on some machines, in which case
- Integer_32'Size = 64, and Integer_32'Last = 2**63-1. Maybe we should
- not call it Integer_32!)
-
-
- 3.12: Since I can always declare my own portable integer types, why would I
- ever want to use the predefined type Integer?
-
- The language itself provides some guidance here. The predefined type
- Integer is used by Ada in the implementation of a number of convenient
- services. The following examples describe some of these services.
- Notice that in most of the following examples, it is unlikely that it
- will ever matter whether or not the predefined type Integer is
- 16-bits, 32-bits, 48-bits, or 64-bits.
-
- a) The exponentiation of X (written X**N) is defined by the language
- for any floating point or integer X, provided N is of type Integer. (N
- should be non-negative for integer X though.)
-
- b) Ada's predefined String type (really just a packed unconstrained
- array of characters) uses an index of subtype Positive (i.e. type
- Integer).
-
- c) The array index in the following "short-hand" array declaration is
- implicitly defined to be type Integer:
-
- A : array(10..40) of Float;
-
-
- d) The loop parameter I in the following for loop is implicitly
- declared type Integer:
-
- for I in 10..40 loop
- ...
- end loop;
-
-
- This application of type Integer is the one most likely to get you
- into portability trouble. If you write: "for I in 1..2**17 loop", then
- you get a constraint error on compilers that make Integer 16-bits,
- because 2**17 is out of range of any Ada 16-bit integer.
-
-
- 3.13: I am learning Ada. Can I experiment with a game program?
-
- Of course. The Public Ada library (FTP wuarchive.wustl.edu) has a
- portable Ada Tetris program in the languages/ada/misc/games directory.
- It uses tasking, keyboard input, and ANSI screen graphics. Have fun!
-
- _________________________________________________________________
-
-
- 4: Advantages of Ada
-
-
- 4.1: Why use Ada?
-
- Think of it like this: We're the kid on the street corner, licking
- that tasty ice cream cone on a hot summer day; an impish grin
- decorates our face as we consume our cool confection. Meanwhile, other
- kids gather round, noticing our pleasure. It matters not a whit that
- they've just had a drink, or had their fill with supper -- they now
- want ice cream. We offer no lecture on how good the ice cream is, we
- simply demonstrate that we are happy, and let their memories carry
- them to the nearest ice cream truck.
-
- (Sorry, I got a little carried away --DW).
-
-
- 4.2: Ada seems large and complex, why is it this way?
-
- (Robert Dewar, lead designer of the GNU Ada compiler, responds):
-
- During the Ada 9X development process we have often had fierce
- arguments over the need to simplify proposals, and I pointed out some
- time ago that the idea of simplicity is heavily overloaded:
- * simple to implement
- * simple to describe informally
- * simple to describe formally
- * results in simple programs
- * simple to understand and/or remember
- * short to describe
-
-
- None of these goals are quite the same, and often they severely
- conflict.
-
- If you listen to programming language design types, especially from
- universities, they often have very little experience in programming,
- and especially little experience in writing large delivered,
- maintained software. That doesn't mean they know nothing about
- programming languages, but it does tend to mean that their view of
- complexity is skewed, and in particularly concentrates on the
- simplicity of the language itself, rather than on the simplicity of
- resulting programs.
-
- A lot of the creative tension in the 9X design process arose from this
- same fundamental dichotomy. The design team tended to have a high
- tolerance for language complexity (partly because they were very good
- at understanding language details), but had a lot of experience in
- actual large scale programming, and so their idea of simplicity was
- biased heavily to simplifying Ada programs. The opposite voice,
- worried about the simplicity of the language itself, represented by a
- section of the DR's and ISO group (who, being a larger more diverse
- group tended to reflect a wider view), considered that the design team
- had gone too far in this direction. If you want to get a feel for the
- transitions, look at the early versions of the 9X ILS, particularly
- version 1.0.
-
- In retrospect, I think we came up with what is at least very close the
- optimal balance. Tuck can speak for himself here more clearly than I
- can speak for him, but I would guess that he and the other members of
- the team recognize that you have to be able to sell the resulting
- design as an acceptably simple whole, and thus must step back from the
- most extensive proposals, while on the other hand, the more
- conservative KISS sentiments were convinced to accept more features
- than they originally felt comfortable with because of convincing
- programming examples and discussions of resulting programming
- complexity. The third wing of opinion ("I don't care what you think,
- but if we can't implement it, then it's not much use!") was also
- effectively fed in from the user-implementor teams.
-
- Is the result too complex? Time will tell, but I think the balance is
- a successful blend.
-
- I am a little more worried about C++ since there is an even greater
- danger of kitchen sink mentality, fueled by lots of enthusiastic
- feature-hungry programmers, adding too much to C++. A lot of big new
- features have been added to C++ recently (notably templates and
- exceptions). It's not that these new features are useless (after all
- Ada programmers know the value of generics and exceptions!) but there
- is a tendency to always add things in a most-decorated form (the
- templates in C++ are much more general, but less safe, than Ada
- generics, and the exceptions in C++ are much more elaborate, but less
- efficient to implement, and trickier to understand). I think it will
- be important for the C++ guys to make a real effort to keep the
- continued development of the language under control to avoid going too
- far in the feature-rich direction.
-
- _________________________________________________________________
-
-
- 5: Object-Oriented Programming with Ada
-
-
- 5.1: Why does Ada have "tagged types" instead of classes?
-
- (Tucker Taft responds):
-
- Someone recently asked me to explain the difference between the
- meaning of the term "class" in C++ and its meaning in Ada 9X. Here is
- a synopsis of the answer:
-
- In C++, the term "class" refers to three different, but related
- things:
- * a language construct, that encapsulates the definitions of data
- members, member functions, nested types, etc.;
-
- * a particular kind of type, defined by a class construct (or by
- "struct" which is a special case of "class");
-
- * a set of types consisting of a type and all of its derivatives,
- direct and indirect.
-
-
- In Ada 9X, the term "class" refers only to the third of the above
- definitions. Ada 9X (and Ada 83) has three different terms for the
- concepts corresponding to the above three things:
- * a "package" encapsulates the definitions of types, objects,
- operations, exceptions, etc which are logically related. (The
- operations of a type defined immediately within the package where
- the type is declared are called, in 9X, the "primitive operations"
- of the type, and in some sense, define the "primitive" semantics
- of the type, especially if it is a private type.)
-
- * a "type" is characterized by a set of values and a set of
- primitive operations (there are a million definitions of "type,"
- unfortunately, but you know what I mean...);
-
- * a "class" is a set of types with similar values and operations; in
- particular, a type and and all of its derivatives, direct and
- indirect, represents a (derivation) class. Also, the set of
- integer types form the integer "class," and so on for the other
- language-defined classes of types in the language.
-
-
- Some OOP languages take an intermediary position. In CLOS, a "class"
- is not an encapsulating construct (CLOS has "packages"). However, a
- "class" is both a type and a set of types, depending on context.
- (Methods "float" freely.)
-
- The distinction Ada 9X makes between types and classes (= set of
- types) carries over into the semantic model, and allows some
- interesting capabilities not present in C++. In particular, in Ada 9X
- one can declare a "class-wide" object initialized by copy from a
- "class-wide" formal parameter, with the new object carrying over the
- underlying type of the actual parameter. For example:
-
- procedure Print_In_Bold (X : T'Class) is
- -- Copy X, make it bold face, and then print it.
- Copy_Of_X : T'Class := X;
- begin
- Make_Bold (Copy_Of_X);
- Print (Copy_Of_X);
- end P;
-
-
- In C++, when you declare an object, you must specify the "exact" class
- of the object -- it cannot be determined by the underlying class of
- the initializing value. Implementing the above procedure in a general
- way in C++ would be slightly more tedious.
-
- Similarly, in Ada 9X one can define an access type that designates
- only one specific type, or alternatively, one can define one that can
- designate objects of any type in a class (a "class-wide" access type).
- For example:
-
- type Fancy_Window_Ptr is access Fancy_Window;
- -- Only points at Fancy Windows -- no derivatives allowed
- type Any_Window_Ptr is access Window'Class;
- -- Points at Windows, and any derivatives thereof.
-
-
- In C++, all pointers/references are "class-wide" in this sense; you
- can't restrict them to point at only one "specific" type.
-
- In other words, C++ makes the distinction between "specific" and
- "class-wide" based on pointer/reference versus object/value, whereas
- in Ada 9X, this distinction is explicit, and corresponds to the
- distinction between "type" (one specific type) and "class" (set of
- types).
-
- The Ada 9X approach we believe (hope ;-) gives somewhat better control
- over static versus dynamic binding, and is less error prone since it
- is type-based, rather than being based on reference vs. value.
-
- In any case, in Ada 9X, C++, and CLOS it makes sense to talk about
- "class libraries," since a given library will generally consist of a
- set of interrelated types. In Ada 9X and CLOS, one could alternatively
- talk about a set of "reusable packages" and mean essentially the same
- thing.
-
-
- 5.2: Variant records seem like a dead feature now? When should I use them
- instead of tagged types?
-
- Hmm, good question.
-
-
- 5.3: What is meant by "interface inheritance" and how does Ada support it?
-
- This answer intentionally left blank.
-
-
- 5.4: How do you do multiple inheritance in Ada 9X?
-
- There is a lengthy paper on the AJPO ftp server (ajpo.sei.cmu.edu)
- titled 9xm-inh.txt under /public/ada9x/docs(?)
-
- That document describes several mechanisms for achieving MI in Ada. It
- is not unusual, however, to find complaints about the syntax and the
- perceived burden it places on the developer. This is what Tucker Taft
- had to say when responging to such a criticism on comp.lang.ada:
-
- Coming up with a syntax for multiple inheritance was not the
- challenge. The challenge was coming up with a set of straightforward
- yet flexible rules for resolving the well known problems associated
- with multiple inheritance, namely:
- * If the same type appears as an ancestor more than once, should all
- or some of its data components be duplicated, or shared? If any
- are duplicated, how are they referenced unambiguously?
-
- * If the same-named (including same parameter/result profile)
- operation is inherited along two paths, how is the ambiguity
- resolved? Can you override each with different code? How do you
- refer to them later?
-
- * Etc...
-
-
- For answers, you can look at the various languages that define a
- built-in approach to multiple inheritance. Unfortunately, you will
- generally get a different answer for each language -- hardly a
- situation that suggests we will be able to craft an international
- consensus. Eiffel uses renaming and other techniques, which seem quite
- flexible, but at least in some examples, can be quite confusing (where
- you override "B" to change what "A" does in some distant ancestor).
- C++ has both non-virtual and virtual base clases, with a number of
- rules associated with each, and various limitations relating to
- downcasting and virtual base classes. CLOS uses simple name matching
- to control "slot" merging. Some languages require that all but one of
- the parent types be abstract, data-less types, so only interfaces are
- being inherited; however if the interfaces happen to collide, you
- still can end up with undesirable and potentially unresolvable
- collisions (where you really want different code for same-named
- interfaces inherited from different ancestors).
-
- One argument is that collisions are rare to begin with, so it doesn't
- make much different how they are resolved. That is probably true, but
- the argument doesn't work too well during an open language design
- process -- people get upset at the most unbelievably trivial and
- rarely uses features if not "correctly" designed (speaking from
- experience here ;-).
-
- Furthermore, given that many of the predominant uses of MI (separation
- of interface inheritance from implementation inheritance, gaining
- convenient access to another class's features, has-a relationships
- being coded using MI for convenience, etc.) are already handled very
- well in Ada 9X, it is hard to justify getting into the MI language
- design fray at all. As you nicely point out, the basic inheritance
- model in Ada 9X is simple and elegant. Why clutter it up with a lot of
- relatively ad-hoc rules to handle one particular approach to MI? For
- the rare cases where MI is really critical, the last thing the
- programmer wants in the language is the "wrong" MI approach built in.
-
- So the basic answer is that at this point in the evolution of OO
- language design, it seemed wiser to provide MI building blocks, rather
- than to foist the wrong approach on the programmer, and be regretting
- it and working around it for years to come.
-
- Perhaps [Douglas Arndt] said it best...
-
- Final note: inheritance is overrated, especially MI. ...
-
-
- If the only or primary type composition mechanism in the language is
- based on inheritance, then by all means, load it up. But Ada 9X
- provides several efficient and flexible type composition mechanisms,
- and there is no need to overburden inheritance with unnecessary and
- complicated baggage.
-
-
- 5.5: Why are Controlled types so, well, strange?
-
- (Tucker Taft responds):
-
- We considered many approaches to user-defined finalization and
- user-defined assignment. Ada presents challenges that make it harder
- to define assignment than in other languages, because assignment is
- used implicitly in several operations (by-copy parameter passing,
- function return, aggregates, object initialization, initialized
- allocators, etc.), and because Ada has types whose set of components
- can be changed as a result of an assignment.
-
- For example:
-
- type T (D : Boolean := False) is record
- case D is
- when False => null;
- when True => H : In_Hands;
- end case;
- end record;
-
- X,Z : T;
- Y : T := (True, H => ...);
-
- ...
-
- X := Y; -- "X.H" component coming into existence
- Y := Z; -- "Y.H" component going out of existence
-
-
- With a type like the one above, there are components that can come and
- go as a result of assignment. The most obvious definition of
- assignment would be:
-
- procedure ":="(Left : in out In_Hands; Right : in In_Hands);
-
-
- Unfortunately, this wouldn't work for the "H" component, because there
- is no preexisting "In_Hands" component to be assigned into in the
- first case, and in the second case, there is no "In_Hands" component
- to assign "from."
-
- Therefore, we decided to decompose the operation of assignment into
- separable pieces: finalization of the left hand side; simple copying
- of the data from the right hand side to the left hand side; and then
- adjustment of the new left hand side. Other decompositions are
- probably possible, but they generally suffer from not being easily
- composable, or not handling situations like the variant record above.
-
- You seem to be proposing a function named ":=" that presumably returns
- a copy of its in parameter. However, to do anything interesting it
- will have to copy the in parameter into a local variable, and then
- "fiddle" with than local variable (essentially what "Adjust" does),
- and then return that local variable (which will make yet another
- copy). The returned result will have to be put back into the desired
- place (which might make yet another copy). For a large object, this
- might involve several extra copies.
-
- By having the user write just that part of the operation that
- "fiddles" with the result after making a copy, we allow the
- implementation to eliminate redundant copying. Furthermore, some
- user-defined representations might be position dependent. That is, the
- final "fiddling" has to take place on the object in its final
- location. For example, one might want the object to point to itself.
- If the implementation copies an object after the user code has
- adjusted it, such self-references will no longer point to the right
- place.
-
- So, as usual, once one gets into working out the details and all the
- interactions, the "obvious" proposal (such as a procedure ":=") no
- longer looks like the best answer, and the best answer one can find
- potentially looks "clumsy" (at least before you try to work out the
- details of the alternatives).
-
-
- Archive-name: computer-lang/Ada/programming/part2
- Comp-lang-ada-archive-name: programming/part2
- Posting-Frequency: monthly
- Last-modified: 7 February 1995
- Last-posted: 19 January 1995
-
- Ada Programmer's
- Frequently Asked Questions (FAQ)
-
- IMPORTANT NOTE: No FAQ can substitute for real teaching and
- documentation. There is an annotated list of Ada books in the
- companion comp.lang.ada FAQ.
-
- This is part 2 of a 3-part posting.
- Part 3 begins with question 9.4; it should be the next posting in this thread.
- Part 1 should be the previous posting in this thread.
-
-
- 5.6: What do "covariance" and "contravariance" mean, and does Ada support
- either or both?
-
- (From Robert Martin) [This is C++ stuff, it must be completely
- re-written for Ada. --MK]
-
-
- R> covariance: "changes with"
- R> contravariance: "changes against"
-
- R> class A
- R> {
- R> public:
- R> A* f(A*); // method of class A, takes A argument and returns A
- R> A* g(A*); // same.
- R> };
-
- R> class B : public A // class B is a subclass of class A
- R> {
- R> public:
- R> B* f(B*); // method of class B overrides f and is covariant.
- R> A* g(A*); // method of class B overrides g and is contravariant.
- R> };
-
- R> The function f is covariant because the type of its return value and
- R> argument changes with the class it belongs to. The function g is
- R> contravariant because the types of its return value and arguments does not
- R> change with the class it belongs to.
-
-
- Actually, I would call g() invariant. If you look in Sather, (one of
- the principle languages with contravariance), you will see that the
- method in the decendent class actually can have aruments that are
- superclasses of the arguments of its parent. So for example:
-
- class A : public ROOT
- {
- public:
- A* f(A*); // method of class A, takes A argument and returns A
- A* g(A*); // same.
- };
-
- class B : public A // class B is a subclass of class A
- {
- public:
- B* f(B*); // method of class B overrides f and is covariant.
- ROOT* g(ROOT*); // method of class B overrides g and is contravariant.
- };
-
-
- To my knowledge the uses for contravariance are rare or nonexistent.
- (Anyone?). It just makes the rules easy for the compiler to type
- check. On the other hand, co-variance is extremely useful. Suppose you
- want to test for equality, or create a new object of the same type as
- the one in hand:
-
- class A
- {
- public:
- BOOLEAN equal(A*);
- A* create();
- }
-
- class B: public A
- {
- public:
- BOOLEAN equal(B*);
- B* create();
- }
-
-
- Here covariance is exactly what you want. Eiffel gives this to you,
- but the cost is giving up 100% compile time type safety. This seem
- necessary in cases like these.
-
- In fact, Eiffel gives you automatic ways to make a method covariant,
- called "anchored types". So you could declare, (in C++/eiffese):
-
- class A
- {
- public:
- BOOLEAN equal(like Current *);
- like Current * create();
- }
-
-
- Which says equal takes an argument the same type as the current
- object, and create returns an object of the same type as current. Now,
- there is not even any need to redeclare these in class B. Those
- transformations happen for free!
-
-
- 5.7: What is meant by upcasting/expanding and downcasting/narrowing?
-
- (Tucker Taft replies):
-
- Here is the symmetric case to illustrate upcasting and downcasting.
-
- type A is tagged ...; -- one parent type
-
- type B is tagged ...; -- another parent type
-
- ...
-
- type C; -- the new type, to be a mixture of A and B
-
- type AC (Obj : access C'Class) is
- new A
- with ...;
- -- an extension of A to be mixed into C
-
- type BC (Obj : access C'Class) is
- new B
- with ...;
- -- an extension of B to be mixed into C
-
- type C is
- tagged limited record
- A : AC (C'Access);
- B : BC (C'Access);
- ... -- other stuff if desired
- end record;
-
-
- We can now pass an object of type C to anything that takes an A or B
- as follows (this presumes that Foobar and QBert are primitives of A
- and B, respectively, so they are inherited; if not, then an explicit
- conversion (upcast) to A and B could be used to call the original
- Foobar and QBert).
-
- XC : C;
- ...
- Foobar (XC.A);
- QBert (XC.B);
-
-
- If we want to override what Foobar does, then we override Foobar on
- AC. If we want to override what QBert does, then we override QBert on
- BC.
-
- Note that there are no naming conflicts, since AC and BC are distinct
- types, so even if A and B have same-named components or operations, we
- can talk about them and/or override them individually using AC and BC.
-
-
- Upcasting (from C to A or C to B) is trivial -- A(XC.A) upcasts to A;
- B(XC.B) upcasts to B.
-
- Downcasting (narrowing) is also straightforward and safe. Presuming XA
- of type A'Class, and XB of type B'Class:
-
- AC(XA).Obj.all downcasts to C'Class (and verifies XA in AC'Class)
- BC(XB).Obj.all downcasts to C'Class (and verifies XB in BC'Class)
-
-
- You can check before the downcast to avoid a Constraint_Error:
-
- if XA not in AC'Class then -- appropriate complaint
-
- if XB not in BC'Class then -- ditto
-
-
- The approach is slightly simpler (though less symmetric) if we choose
- to make A the "primary" parent and B a "secondary" parent:
-
- type A is ...
- type B is ...
-
- type C;
-
- type BC (Obj : access C'Class) is
- new B
- with ...
-
- type C is
- new A
- with record
- B : BC (C'Access);
- ... -- other stuff if desired
- end record;
-
-
- Now C is a "normal" extension of A, and upcasting from C to A and
- (checked) downcasting from C'Class to A (or A'Class) is done with
- simple type conversions. The relationship between C and B is as above
- in the symmetric approach.
-
- Not surprisingly, using building blocks is more work than using a
- "builtin" approach for simple cases that happen to match the builtin
- approach, but having building blocks does ultimately provide mean more
- flexibility for the programmer -- there are many other structures that
- are possible in addition to the two illustrated above, using the
- access discriminant building block.
-
- For example, for mixins, each mixin "flavor" would have an access
- discriminant already:
-
- type Window is ... -- The basic "vanilla" window
-
- -- Various mixins
- type Win_Mixin_1 (W : access Window'Class) is ...
-
- type Win_Mixin_2 (W : access Window'Class) is ...
-
- type Win_Mixin_3 (W : access Window'Class) is ...
-
-
- Given the above vanilla window, plus any number of window mixins, one
- can construct a desired window by including as many mixins as wanted:
-
- type My_Window is Window with
- M1 : Win_Mixin_1 (My_Window'access);
- M3 : Win_Mixin_3 (My_Window'access);
- M11 : Win_Mixin_1(My_Window'access);
- ... -- plus additional stuff, as desired.
- end record;
-
-
- As illustrated above, you can incorporate the same "mixin" multiple
- times, with no naming conflicts. Every mixin can get access to the
- enclosing object. Operations of individual mixins can be overridden by
- creating an extension of the mixin first, overriding the operation in
- that, and then incorporating that tweaked mixin into the ultimate
- window.
-
- I hope the above helps better illustrate the use and flexibility of
- the Ada 9X type composition building blocks.
-
-
- 5.8: How does Ada do "narrowing"?
-
- Dave Griffith said
-
- . . . Nonetheless, The Ada9x committee chose a structure-based
- subtyping, with all of the problems that that is known to cause. As
- the problems of structure based subtyping usually manifest only in
- large projects maintained by large groups, this is _precisely_ the
- subtype paradigm that Ada9x should have avoided. Ada9x's model is,
- as Tucker Taft pointed out, quite easy to use for simple OO
- programming. There is, however, no good reason to _do_ simple OO
- programming. OO programmings gains click in somewhere around 10,000
- LOC, with greatest gains at over 100,000. At these sizes, "just
- declare it tagged" will result in unmaintainable messes. OO
- programming in the large rapidly gets difficult with structure based
- subtyping. Allowing by-value semantics for objects compounds these
- problems. All of this is known. All of this was, seemingly, ignored
- by Ada9x.
-
-
- (Tucker Taft answers)
-
- As explained in a previous note, Ada 9X supports the ability to hide
- the implementation heritage of a type, and only expose the desired
- interface heritage. So we are not stuck with strictly "structure-based
- subtyping." Secondly, by-reference semantics have many "well known"
- problems as well, and the designers of Modula-3 chose to, seemingly,
- ignore those ;-) ;-). Of course, in reality, neither set of language
- designers ignored either of these issues. Language design involves
- tradeoffs. You can complain we made the wrong tradeoff, but to
- continue to harp on the claim that we "ignored" things is silly. We
- studied every OOP language under the sun on which we could find any
- written or electronic material. We chose value-based semantics for
- what we believe are good reasons, based on reasonable tradeoffs.
-
- First of all, in the absence of an integrated garbage collector,
- by-reference semantics doesn't make much sense. Based on various
- tradeoffs, we decided against requiring an integrated garbage
- collector for Ada 9X.
-
- Secondly, many of the "known" problems with by-value semantics we
- avoided, by eliminating essentially all cases of "implicit
- truncation." One of the problems with the C++ version of "value
- semantics" is that on assignment and parameter passing, implicit
- truncation can take place mysteriously, meaning that a value that
- started its life representing one kind of thing gets truncated
- unintentionally so that it looks like a value of some ancestor type.
- This is largely because the name of a C++ class means differnt things
- depending on the context. When you declare an object, the name of the
- class determines the "exact class" of the object. The same thing
- applies to a by-value parameter. However, for references and pointers,
- the name of a class stands for that class and all of its derivatives.
- But since, in C++, a value of a subclass is always acceptable where a
- value of a given class is expected, you can get implicit truncation as
- part of assignment and by-value parameter passing. In Ada 9X, we avoid
- the implicit truncation because we support assignment for "class-wide"
- types, which never implicitly truncates, and one must do an explicit
- conversion to do an assignment that truncates. Parameter passing never
- implicitly truncates, even if an implicit conversion is performed as
- part of calling an inherited subprogram.
-
- In any case, why not either ignore Ada 9X or give it a fair shot? It
- is easy to criticize any particular design decision, but it is much
- harder to actually put together a complete integrated language design
- that meets the requirements of its user community, doesn't bankrupt
- the vendor community, and provides interesting fodder for the academic
- community ;-).
-
- _________________________________________________________________
-
-
- 6: Ada Numerics
-
-
- 6.1: Where can I find anonymous ftp sites for Ada math packages? In particular
- where are the random number generators?
-
-
- bugs.nosc.mil (128.49.4.117)
- Stuff of high quality in pub/ada The random number generator
- and random deviates are recommended. These are mirrored at the
- next site, wuarchive.
-
- ftp.rational.com
- Freeware version of the ISO math packages on Rational's FTP
- server. It's a binding over the C Math library, in
- public/apex/freeware/math_lib.tar.Z
-
- wuarchive.wustl.edu
- Site of PAL, the Public Ada Library: math routines scattered
- about in the directories under languages/ada in particular, in
- subdirectory swcomps
-
- source.asset.com
- This is not an anonymous ftp site for math software. What you
- should do is log on anonymously under ftp, and download the
- file asset.faq from the directory pub. This will tell you how
- to get an account.
-
- ftp.cs.kuleuven.ac.be
- Go to directory pub/Ada-Belgium/cdrom. There's a collection of
- math intensive software in directory swcomps. Mirrors some of
- PAL at wuarchive.wustl.edu.
-
- ajpo.sei.cmu.edu
- Go to directory public/atip/adar to find extended-precision
- decimal arithmetic. Includes facilities for COBOL-like IO.
-
-
- 6.2: How can I write portable code in Ada 83 using predefined types like Float
- and Long_Float? Likewise, how can I write portable code that uses Math
- functions like Sin and Log that are defined for Float and Long_Float?
-
- (from Jonathan Parker)
-
- Ada 83 was slow to arrive at a standard naming convention for
- elementary math functions and complex numbers. Furthermore, you'll
- find that some compilers call the 64-bit floating point type
- Long_Float; other compilers call it Float. Fortunately, it is easy to
- write programs in Ada that are independent of the naming conventions
- for floating point types and independent of the naming conventions of
- math functions defined on those types.
-
- One of the cleanest ways is to make the program generic:
-
- generic
- type Real is digits <>;
- with function Arcsin (X : Real) return Real is <>;
- with function Log (X : Real) return Real is <>;
- -- This is the natural log, inverse of Exp(X), sometimes written Ln(X).
- package Example_1 is
- ...
- end Example_1;
-
-
- So the above package doesn't care what the name of the floating point
- type is, or what package the Math functions are defined in, just as
- long as the floating point type has the right attributes (precision
- and range) for the algorithm, and likewise the functions. Everything
- in the body of Example_1 is written in terms of the abstract names,
- Real, Arcsin, and Log, even though you instantiate it with compiler
- specific names that can look very different:
-
- package Special_Case is new Example_1 (Long_Float, Asin, Ln);
-
-
- The numerical algorithms implemented by generics like Example_1 can
- usually be made to work for a range of floating point precisions. A
- well written program will perform tests on Real to reject
- instantiations of Example_1 if the floating points type is judged
- inadequate. The tests may check the number of digits of precision in
- Real (Real'Digits) or the range of Real (Real'First, Real'Last) or the
- largest exponent of the set of safe numbers (Real'Safe_Emax), etc.
- These tests are often placed after the begin statement of package
- body, as in:
-
- package body Example_1 is
- ...
- begin
- if (Real'Machine_Mantissa > 60) or (Real'Machine_Emax < 256) then
- raise Program_Error;
- end if;
- end Example_1;
-
-
- Making an algorithm as abstract as possible, (independent of data
- types as much as possible) can do a lot to improve the quality of the
- code. Support for abstraction is one of the many things Ada-philes
- find so attractive about the language. The designers of Ada 95
- recognized the value of abstraction in the design of numeric
- algorithms and have generalized many of the features of the '83 model.
- For example, no matter what floating point type you instantiate
- Example_1 with, Ada 95 provides you with functions for examining the
- exponent and the mantissas of the numbers, for truncating, determining
- exact remainders, scaling exponents, and so on. (In the body of
- Example_1, and in its spec also of course, these functions are
- written, respectively: Real'Exponent(X), Real'Fraction(X),
- Real'Truncation(X), Real'Remainder(X,Y), Real'Scaling(X, N). There are
- others.) Also, in package Example_1, Ada 95 lets you do the arithmetic
- on the base type of Real (called Real'Base) which is liable to have
- greater precision and range than type Real.
-
- It is rare to see a performance loss when using generics like this.
- However, if there is an unacceptable performance hit, or if generics
- cannot be used for some other reason, then subtyping and renaming will
- do the job. Here is an example of renaming:
-
- with Someones_Math_Lib;
- procedure Example_2 is
-
- subtype Real is Long_Float;
-
- package Math renames Someones_Math_Lib;
- function Arcsin(X : Real) return Real renames Math.Asin
- function Log (X : Real) return Real renames Math. Ln;
-
- -- Everything beyond this point is abstract with respect to
- -- the names of the floating point (Real), the functions (Arcsin
- -- and Log), and the package that exported them (Math).
- ...
- end Example_2;
-
-
- I prefer to make every package and subprogram (even test procedures)
- as compiler independent and machine portable as possible. To do this
- you move all of the renaming of compiler dependent functions and all
- of the "withing" of compiler dependent packages to a single package.
- In the example that follows, its called Math_Lib_8. Math_Lib_8 renames
- the 8-byte floating point type to Real_8, and makes sure the math
- functions follow the Ada 95 standard, at least in name. In this
- approach Math_Lib_8 is the only compiler dependent component.
-
- There are other, perhaps better, ways also. See for example, "Ada In
- Action", by Do-While Jones for a generic solution.
-
- Here's the spec of Math_Lib_8, which is a perfect subset of package
- Math_Env_8, available by FTP in file
- ftp://lglftp.epfl.ch/pub/Ada/FAQ/math_env_8.ada
-
-
- --***************************************************************
- -- Package Math_Lib_8
- --
- -- A minimal math package for Ada 83: creates a standard interface to vendor
- -- specific double-precision (8-byte) math libraries. It renames the 8 byte
- -- Floating point type to Real_8, and uses renaming to create
- -- (Ada 95) standard names for Sin, Cos, Log, Sqrt, Arcsin, Exp,
- -- and Real_8_Floor, all defined for Real_8.
- --
- -- A more ambitious but perhaps less efficient
- -- package would wrap the compiler specific functions in function calls, and
- -- do error handling on the arguments to Ada 95 standards.
- --
- -- The package assumes that Real_8'Digits > 13, and that
- -- Real_8'Machine_Mantissa < 61. These are asserted after the
- -- begin statement in the body.
- --
- -- Some Ada 83 compilers don't provide Arcsin, so a rational-polynomial+
- -- Newton-Raphson method Arcsin and Arccos pair are provided in the body.
- --
- -- Some Ada 83 compilers don't provide for truncation of 8 byte floats.
- -- Truncation is provided here in software for Compilers that don't have it.
- -- The Ada 95 function for truncating (toward neg infinity) is called 'Floor.
- --
- -- The names of the functions exported below agree with the Ada9X standard,
- -- but not, in all likelihood the semantics. It is up to the user to
- -- be careful...to do his own error handling on the arguments, etc.
- -- The performance of these function can be non-portable,
- -- but in practice they have their usual meanings unless you choose
- -- weird arguments. The issues are the same with most math libraries.
- --***************************************************************
-
- --with Math_Lib; -- Meridian DOS Ada.
- with Long_Float_Math_Lib; -- Dec VMS
- --with Ada.Numerics.Generic_Elementary_Functions; -- Ada9X
- package Math_Lib_8 is
-
- --subtype Real_8 is Float; -- Meridian 8-byte Real
- subtype Real_8 is Long_Float; -- Dec VMS 8-byte Real
-
- --package Math renames Math_Lib; -- Meridian DOS Ada
- package Math renames Long_Float_Math_Lib; -- Dec VMS
- --package Math is new Ada.Numerics.Generic_Elementary_Functions(Real_8);
-
- -- The above instantiation of the Ada.Numerics child package works on
- -- GNAT, or any other Ada 95 compiler. Its here if you want to use
- -- an Ada 95 compiler to compile Ada 83 programs based on this package.
-
- function Cos (X : Real_8) return Real_8 renames Math.Cos;
- function Sin (X : Real_8) return Real_8 renames Math.Sin;
- function Sqrt(X : Real_8) return Real_8 renames Math.Sqrt;
- function Exp (X : Real_8) return Real_8 renames Math.Exp;
-
- --function Log (X : Real_8) return Real_8 renames Math.Ln; -- Meridian
- function Log (X : Real_8) return Real_8 renames Math.Log; -- Dec VMS
- --function Log (X : Real_8) return Real_8 renames Math.Log; -- Ada 95
-
- --function Arcsin (X : Real_8) return Real_8 renames Math.Asin; -- Dec VMS
- --function Arcsin (X : Real_8) return Real_8 renames Math.Arcsin; -- Ada 95
- function Arcsin (X : Real_8) return Real_8;
- -- Implemented in the body. Should work with any compiler.
-
- --function Arccos (X : Real_8) return Real_8 renames Math.Acos; -- Dec VMS
- --function Arccos (X : Real_8) return Real_8 renames Math.Arccos; -- Ada 95
- function Arccos (X : Real_8) return Real_8;
- -- Implemented in the body. Should work with any compiler.
-
- --function Real_8_Floor (X : Real_8) return Real_8 renames Real_8'Floor;-- 95
- function Real_8_Floor (X : Real_8) return Real_8;
- -- Implemented in the body. Should work with any compiler.
-
- end Math_Lib_8;
-
-
- 6.3: Where's a good place to start learning the Ada 95 numerics model?
-
- (from Jonathan Parker)
-
- Start with the Ada 95 Rationale. Part 3 of the Rationale, Section 1.3
- provides a good introduction, with examples on use of elementary
- function packages. Part 3 of the Rationale, Section 6.1 discusses the
- design of the Complex number and Complex function packages. Section 6
- reviews the numerics annex, especially attributes and accuracy
- requirement.
-
- The Rationale can be obtained by anonymous ftp from ajpo.sei.cmu.edu.
- Another site to get the Ada 95 Rationale from is the Ada WWW homepage
- at http://lglwww.epfl.ch/Ada/ .
-
- The Ada 95 Reference Manual describes the Real valued elementary Math
- functions, the Random number packages, and the floating point
- attributes in section A5 (page 295). The Ada 95 Reference Manual may
- be obtained by anonymous ftp from ajpo.sei.cmu.edu, in directory
- public/ada9x/rm9x.
-
-
- 6.4: How do I get Real valued and Complex valued math functions in Ada 95?
-
- (from Jonathan Parker)
-
- Complex type and functions are provided by compilers that support the
- numerics Annex. The packages that use Float for the Real number and
- for the Complex number are:
-
- Ada.Numerics.Elementary_Functions;
- Ada.Numerics.Complex_Types;
- Ada.Numerics.Complex_Elementary_Functions;
-
-
- The packages that use Long_Float for the Real number and for the
- Complex number are:
-
- Ada.Numerics.Long_Elementary_Functions;
- Ada.Numerics.Long_Complex_Types;
- Ada.Numerics.Long_Complex_Elementary_Functions;
-
-
- The generic versions are demonstrated in the following example. Keep
- in mind that the non-generic packages may have been better tuned for
- speed or accuracy. In practice you won't always instantiate all three
- packages at the same time, but here is how you do it:
-
- with Ada.Numerics.Generic_Complex_Types;
- with Ada.Numerics.Generic_Elementary_Functions;
- with Ada.Numerics.Generic_Complex_Elementary_Functions;
-
- procedure Do_Something_Numerical is
-
- type Real_8 is digits 15;
-
- package Real_Functions_8 is
- new Ada.Numerics.Generic_Elementary_Functions (Real_8);
-
- package Complex_Nums_8 is
- new Ada.Numerics.Generic_Complex_Types (Real_8);
-
- package Complex_Functions_8 is
- new Ada.Numerics.Generic_Complex_Elementary_Functions
- (Complex_Nums_8);
-
- use Real_Functions_8, Complex_Nums_8, Complex_Functions_8;
- ...
- ... -- Do something
- ...
- end Do_Something_Numerical;
-
-
- 6.5: What libraries or public algorithms exist for Ada?
-
- An Ada version of Fast Fourier Transform is available. It's in
- journal "Computers & Mathematics with Applications," vol. 26, no. 2,
- pp. 61-65, 1993, with the title:
-
- "Analysis of an Ada Based Version of Glassman's General N Point Fast
- Fourier Transform"
-
- The package is now available in the AdaNET repository, object #: 6728,
- in collection: Transforms. If you're not an AdaNET user, contact Peggy
- Lacey (lacey@rbse.mountain.net).
-
- _________________________________________________________________
-
-
- 7: Efficiency of Ada Constructs
-
-
- 7.1: How much extra overhead do generics have?
-
- If you overgeneralize the generic, there will be more work to do for
- the compiler. How do you know when you have overgeneralized? For
- instance, passing arithmetic operations as parameters is a bad sign.
- So are boolean or enumeration type generic formal parameters. If you
- never override the defaults for a parameter, you probably
- overengineered.
-
- Code sharing (if implemented and requested) will cause an additional
- overhead on some calls, which will be partially offset by improved
- locality of reference. (Translation, code sharing may win most when
- cache misses cost most.) If a generic unit is only used once in a
- program, code sharing always loses.
-
- R.R. Software chose code sharing as the implementation for generics
- because 2 or more instantiations of Float_Io in a macro implementation
- would have made a program too large to run in the amount of memory
- available on the PC machines that existed in 1983 (usually a 128k or
- 256k machine).
-
- Generics in Ada can also result in loss of information which could
- have helped the optimizer. Since the compiler is not restricted by Ada
- staticness rules within a single module, you can often avoid penalties
- by declaring (or redeclaring) bounds so that they are local:
-
- package Global is
- subtype Global_Int is
- Integer range X..Y;
-
- ...
- end Global;
-
-
- with Global;
- package Local is
- subtype Global_Int is
- Global.Global_Int;
-
- package Some_Instance is
- new Foo (Global_Int);
-
- ...
- end Local;
-
-
- Ada rules say that having the subtype redeclared locally does not
- affect staticness, but on a few occasions optimizers have been caught
- doing a much better job. Since optimizers are constantly changing,
- they may have been caught just at the wrong time.
-
- _________________________________________________________________
-
-
- 8: Advanced Programming Techniques with Ada
-
-
- 8.1: Does Ada have automatic constructors and destructors?
-
- (Tucker Taft replies)
-
- At least in Ada 9X, functions with controlling results are inherited
- (even if overriding is required), allowing their use with dynamic
- binding and class-wide types. In most other OOPs, constructors can
- only be called if you know at compile time the "tag" (or equivalent)
- of the result you want. In Ada 9X, you can use the tag determined by
- the context to control dispatching to a function with a controlling
- result. For example:
-
- type Set is abstract tagged private;
- function Empty return Set is abstract;
- function Unit_Set(Element : Element_Type) return Set is abstract;
- procedure Remove(S : in out Set; Element : out Element_Type) is abstract;
- function Union(Left, Right : Set) return Set is abstract;
- ...
-
- procedure Convert(Source : Set'Class; Target : out Set'Class) is
- -- class-wide "convert" routine, can convert one representation
- -- of a set into another, so long as both set types are
- -- derived from "Set," either directly or indirectly.
-
- -- Algorithm: Initialize Target to the empty set, and then
- -- copy all elements from Source set to Target set.
-
- Copy_Of_Source : Set'Class := Source;
- Element : Element_Type;
- begin
- Target := Empty; -- Dispatching for Empty determined by Target'Tag.
-
- while Copy_Of_Source /= Empty loop
- -- Dispatching for Empty based on Copy_Of_Source'Tag
-
- Remove_Element(Copy_Of_Source, Element);
-
- Target := Union(Target, Unit_Set(Element));
- -- Dispatching for Unit_Set based on Target'Tag
- end loop;
- end Convert;
-
-
- The functions Unit_Set and Empty are essentially "constructors" and
- hence must be overridden in every extension of the abstract type Set.
- However, these operations can still be called with a class-wide
- expected type, and the controlling tag for the function calls will be
- determined at run-time by the context, analogous to the kind of
- (compile-time) overload resolution that uses context to disambiguate
- enumeration literals and aggregates.
-
-
- 8.2: How can I redefine assignment operations?
-
- See "Tips and Tidbits #1: User Defined Assignment" by Brad Balfour
- (where is this located?)
-
-
- 8.3: Should I stick to a one package, one type approach while writing Ada
- software?
-
- (Robb Nebbe responds)
-
- Off hand I can think of a couple of advantages from separating the
- concepts of type and module in Ada.
-
- Separation of visibility and inheritance allows a programmer to
- isolate a derived type from the implementation details of its parent.
- To put it another way information hiding becomes a design decision
- instead of a decision that the programming language has already made
- for you.
-
- Another advantage that came "for free" is the distinction between
- subtyping and implementation inheritance. Since modules and types are
- independent concepts the interaction of the facilities for information
- hiding already present in Ada83 with inheritance provide an elegant
- solution to separating subtyping from implementation inheritance. (In
- my opinion more elegant than providing multiple forms of inheritance
- or two distinct language constructs.)
-
-
- 8.4: What is the "Beaujolais Effect"?
-
- The "Beaujolais Effect" is detrimental, and language designers should
- try to avoid it. But what is it?
-
- (from Tucker Taft)
-
- The term "Beaujolais Effect" comes from a prize (a bottle of
- Beaujolais) offered by Jean Ichbiah during the original Ada design
- process to anyone who could find a situation where adding or removing
- a single "use" clause could change a program from one legal
- interpretation to a different legal interpretation. (Or equivalently,
- adding or removing a single declaration from a "use"d package.)
-
- At least one bottle was awarded, and if the offer was still open, a
- few more might have been awarded during the Ada 9X process. However,
- thanks to some very nice analysis by the Ada 9X Language Precision
- Team (based at Odyssey Research Associates) we were able to identify
- the remaining cases of this effect in Ada 83, and remove them as part
- of the 9X process.
-
- The existing cases in Ada 83 had to do with implicit conversion of
- expressions of a universal type to a non-universal type. The rules in
- Ada 9X are subtly different, making any case that used to result in a
- Beaujolais effect in Ada 83, illegal (due to ambiguity) in Ada 9X.
-
- The Beaujolais effect is considered "harmful" because it is expected
- that during maintenance, declarations may be added or removed from
- packages without being able to do an exhaustive search for all places
- where the package is "use"d. If there were situations in the language
- which resulted in Beaujolais effects, then certain kinds of changes in
- "use"d packages might have mysterious effects in unexpected places.
-
- (from Jean D. Ichbiah)
-
- It is worth pointing that many popular languages have Beaujolais
- effect: e.g. the Borland Pascal "uses" clause, which takes an
- additive, layer-after-layer, interpretation of what you see in the
- used packages (units) definitely exhibits a Beaujolais effect.
-
- Last time I looked at C++, my impression was that several years of
- Beaujolais vintage productions would be required.
-
- For component-based software development, such effects are undesirable
- since your application may stop working when you recompile it with the
- new -- supposedly improved -- version of a component.
-
-
- 8.5: What about the "Ripple Effect"?
-
- (Tucker Taft explains)
-
- We have eliminated all remnants of the Beaujolais Effect, but we did
- debate various instances of the "Ripple" effect during the language
- revision process (apologies to Gallo Ripple Wine enthusiasts ;-).
-
- In brief, the (undesirable) Ripple effect was related to whether the
- legality of a compilation unit could be affected by adding or removing
- an otherwise unneeded "with" clause on some compilation unit on which
- the unit depended, directly or indirectly.
-
- This issue came up at least twice. One when we were considering rules
- relating to use of attributes like 'Address. In Ada 83 as interpreted
- by the ARG, if a compilation unit contains a use of 'Address, then
- there must be a "with" of package System somewhere in the set of
- library unit specs "with"ed by the compilation unit (directly or
- indirectly).
-
- In Ada 9X, we have eliminated this rule, as it was for some compilers
- an unnecessary implementation burden, and didn't really provide any
- value to the user (if anything, it created some confusion). The rule
- now is that the use of an attibute that returns a value of some
- particular type makes the compilation unit semantically dependent on
- the library unit in which the type is declared (whether or not it is
- "with"ed).
-
- The second place the Ripple effect came up was when we were trying to
- provide automatic direct visibility to (primitive) operators.
- Ultimately we ended up with an explicit "use type" clause for making
- operators directly visible. For a while we considered various rules
- that would make all primitive operators directly visible; some of the
- rules considered created the undesirable "Ripple" effects; others
- created annoying incompatibilities; all were quite tricky to implement
- correctly and efficiently.
-
- _________________________________________________________________
-
-
- 9: Ada and Other Programming Languages
-
-
- 9.1: Where can I find programs that will translate from (some language) to
- Ada?
-
- (Job Honig)
-
- Probably not the answer you like to hear, but my advice would be to
- redesign the code, employing your knowledge of the current system, of
- course. I have done this twice, once for Coco, a parser generator for
- LALR left attributed grammars, and once for Flex, the well known
- scanner generator. Both attempts revealed errors in the original
- software, that were uncovered by designing the new system using the
- higher abstraction level allowed by Ada...
-
- So I would support your requirements analysis (transition to Ada), but
- not your proposed implementation (using a source code translator).
-
- (no longer Job Honig :-)
-
- Otherwise, it is generally advisable to simply interface to code that
- already works. Still, you may have compelling reasons to translate
- your existing source to Ada. In that case, here is a list of available
- translators:
-
- * Pascal to Ada:
-
- R.R. Software's Pastran program (Pascal to Ada Translator).
-
- To see the differences in programming style, see "Ada for
- Experienced Programmers", by A. Nico Habermann and Dewayne E.
- Perry (Addison-Wesley Pub. Co., Reading, Mass., 1983). Covers Ada
- and Pascal.
-
- * Fortran to Ada: ???
-
- * COBOL to Ada: ???
-
- * C++ to Ada: ???
-
- * C to Ada: ???
-
- * Modula-2 to Ada:
-
- (from Wayne R. Lawton)
- The Idaho National Engineering Laboratory (INEL), a Dept of Energy
- Lab has a basic capability for Modula-2 to Ada-83. The tool is
- "research grade" quality, but may provide a starting point for
- what you need. This is the same group of people who brought you
- AdaSAGE. Give them a ring at (208) 526-0656. This is an answer
- desk hotline in the section that wrote the tool.
-
- If you are looking for commercial quality, I wish you the best of
- luck. If you just need something to perform 80% of the grunt code
- translation, I think this might meet your needs. I know of two
- systems comprising about 250,000 lines of code that were
- originally developed in Modula-2 then translated and cleaned up in
- Ada 83 after Alsys 1.0 for the PC came out back around 1987.
-
- * Visual Basic to Ada: NOT! :-)
-
-
- 9.2: How can I convert Ada 83 sources to Ada 9X?
-
- First you should read the following document, which will provide you
- with much useful information: "Changes to Ada -- 1987 to 1995", file
- ch83.{ps,doc}, in directory
- ftp://ajpo.sei.cmu.edu/public/ada9x/mrtcomments/rm9x/v5.95
-
- If you're using GNAT, the tool you are probably looking for is
- "gnatchop". In csh you could use something like this to quickly
- process existing files:
-
- cd dest_dir # The destination directory
- foreach f ( ../src_dir/*.a ) # ../src_dir is the source directory
- gnatchop $f
- end
-
- gnatchop will show you what sources are causing problems.
-
-
- 9.3: I hear that Ada is slower than Fortran or C, is that true?
-
- First, note that you are comparing compilers, not languages. There is
- no such thing as "fast" Ada code any more than there is "fast" C++ or
- Fortran code. Now, when comparing execution speeds on similar
- platforms, you must keep in mind the optimization levels, OS tuning,
- etc. while making the comparisons. The bottom line is that
- benchmarking, especially between two different languages, requires
- _very_ careful measurement. In general, such results should be viewed
- with caution.
-
- (A message from Bevin Brett of DEC)
-
- I have been asked to comment on the relative performance of algorithms
- coded in Ada and in Fortran.
-
- This question has come up repeatedly over the years, and deserves a
- complete answer, rather than a simplistic one.
-
- There are many factors which influence the size and execution speed of
- the running program, and they all play together to get a full answer.
- I shall then discuss an exact Ada v. Fortran comparison that Digital
- was involved in.
-
- First, a position statement: The variation between Ada and Fortran is
- less than the variation within the language caused by the exact
- implementation details. A person versed in the Ada issues should do as
- well in Ada as a person versed in the Fortran issues will do in
- Fortran. The size and execution speed of the result should be within a
- few percent of each other.
-
- (a) Differences due to the compiler
-
- In the case of the DEC Ada and Fortran compilers, the optimizer and
- code generator are the same. Never-the-less, the exact inputs into
- the optimizer and code generator may differ slightly when the same
- algorithm is compiled by the Ada and Fortran compilers, and this
- can result in major differences in the generated code. In these
- cases the compiler front ends can usually be modified to correct
- the slower one.
-
- We have not observed any major differences in generated code
- quality between the DEC Ada and DEC Fortran compilers caused by
- such issues.
-
-
- (b) Differences due to the language
-
- It is very important that the same algorithm be written in the two
- languages. The biggest differences we have observed are
- 1. Having the wrong dimension varying fastest, since it is
- desireable to have the first dimension changing fastest in
- Fortran, and the last dimension in Ada. Thus when an
- algorithm is transliterated, the array indexes must be
- reversed.
-
- 2. Using compile-time-known bounds for arrays in Fortran, and
- using unconstrained arrays in the Ada code. Knowing the exact
- values of the dimensions at compile-time results in much
- better code.
-
- 3. Not suppressing all the runtime checks in Ada. The Fortran
- compiler assumes all array bounds are in range, and all
- arithmetic operations do not overflow. You must use a pragma
- Suppress to tell this to the Ada compiler as well.
-
- 4. Don't use arrays of Ada Booleans to match arrays of Fortran
- Integers, because accessing bytes on a RISC system might be
- much worse than accessing fullwords.
-
-
- (c) Differences due to the bindings
-
- The biggest bindings differences are related to Fortran's built-in
- support for complex types, and for various math routines such as
- SQRT and SIN, compared with Ada code that often uses hand-coded or
- ISO standardised versions of these functions with different
- requirements than are imposed on the Fortran versions.
-
- DEC Ada has built-in support for complex types, and also has
- bindings directly to the same primitives that Fortran uses for its
- math routines and so gets the same performance as Fortran does.
-
-
- (d) Differences due to the author
-
- The use of good Ada and Fortran style can also effect the generated
- code. Provided the author writes in good Ada style, and follows
- the above guidelines, the generated code should do as well as
- Fortran.
-
-
- The Ada Performance Benchmark
-
- A DEC Ada customer had a Fortran benchmark that had been translated
- into Ada without awareness of the above issues, and was running
- substantially slower with DEC Ada than the original was with DEC
- Fortran.
-
- Bevin Brett, a DEC Ada team member, developed the above guidelines in
- the process of retranslating the code into Ada.
-
- Portions of this translation are shown here (a) as an illustration of
- the application of the above rules, and (b) as an illustration of the
- kind of operations that were present in the benchmark.
-
- The whole benchmark has not been provided to avoid possible issues of
- ownership.
-
- The resulting Ada benchmark components each ran within a few percent
- of their Fortran counterparts. The Ada code is available by FTP, in
- file ftp://lglftp.epfl.ch/pub/Ada/FAQ/ada-vs-fortran.ada
-
-
- Archive-name: computer-lang/Ada/programming/part3
- Comp-lang-ada-archive-name: programming/part3
- Posting-Frequency: monthly
- Last-modified: 7 February 1995
- Last-posted: 19 January 1995
-
- Ada Programmer's
- Frequently Asked Questions (FAQ)
-
- IMPORTANT NOTE: No FAQ can substitute for real teaching and
- documentation. There is an annotated list of Ada books in the
- companion comp.lang.ada FAQ.
-
- This is part 3 of a 3-part posting.
- Part 2 begins with question 5.6.
- Parts 1 and 2 should be the previous postings in this thread.
-
-
- 9.4: Isn't Ada less "elegant" than Eiffel?
-
- While it is true that programming-language support for "assertions"
- is an important contribution of Eiffel to software construction, this
- is not an issue of "elegance", and there are many other important
- factors to consider.
-
- Note also that preconditions and postconditions can be fairly easily
- and efficiently included in Ada code. Invariants seem difficult to
- emulate directly in Ada. If you're really interested in the formal use
- of assertions with Ada, maybe Anna is a solution for you.
-
- (Tucker Taft comments)
-
- I guess one thing that bothers me a little is that people are quick to
- say that Eiffel is "elegant" without really looking at it. I fear that
- such statements will become self-fulfilling prophecies, with those
- programmers interested in elegance migrating over to Eiffel rather
- than sticking with Ada.
-
- In particular, although I like the assertion stuff in Eiffel, I think
- the language has a number of "inelegant" aspects. For example:
-
- 1. exception handlers only at the top level of a routine, with the
- only way to "handle" an exception being by retrying the whole
- routine.
-
- 2. No way to return from a routine in the middle. This makes it a
- pain in the neck to search through a list for something in a loop,
- and then return immediately when you find what you want. (I have
- never found the addition of extra boolean control variable a help
- to the understanding of an algorithm.)
-
- 3. Namespace control handled by a separate sublanguage, and no real
- higher level concept of "module" or "subsystem."
-
- 4. An obscure notation like "!!" being used for an important and
- frequent operation (construction).
-
- 5. No way to conveniently "use" another abstraction without
- inheriting from it.
-
- 6. No strong distinctions between integer types used for array
- indexing.
-
- 7. Using the same operator ":=" for both (aliasing) pointer
- assignment, and for value assignment, depending on whether the
- type is "expanded." (Simula's solution was far preferable, IMHO).
-
- And most critically:
-
-
- 8. No separate interface for an abstraction. You can view a interface
- by running a tool, but this misses completely the importance of
- having a physical module that represents the interface, and acts
- as a contract between the specifier or user of an abstraction and
- its implementor. In Eiffel, one might not even be truly aware when
- one is changing the interface to an abstraction, because there is
- no particular physical separation between interface and
- implementation.
-
-
- I consider many of the above problems quite serious, with some of them
- being real throwbacks to the old style of programming languages where
- there were no well defined interfaces or modules.
-
- Hence, I cringe a bit when people say that Eiffel is the "most
- elegant" OOP and that they would use it if only it were practical to
- do so. In many ways, I think Ada is much better human-engineered than
- Eiffel, with important things like range constraints built into the
- language in a way that makes them convenient to use. Although general
- assertions are nice, they don't give you the kind of line-by-line
- consistency checks that Ada can give you.
-
- To summarize --
- Although Eiffel certainly has a number of nice features, I don't
- consider it ready for prime time as far as building and maintaining
- large systems with large numbers of programmers. And from a human
- engineering point of view, I think Ada is significantly better.
-
-
- 9.5: Are there any papers detailing the differences between Ada and C++?
-
- Below are two references. Bear in mind that it is difficult to make
- such a comparison without exposing biases. However, the two papers
- below are well worth reading.
-
- "A Comparison of the OO features of Ada9x and C++" in Springer Lecture
- Notes in CS: "Ada Europe 93" pp.125-141 (short paper, good reading,
- enlightens idioms)
-
- ftp ajpo.sei.cmu.edu in directory: /public/ada9x, document:
- 9x_cplus.hlp
-
-
- 9.6: I keep hearing that Ada is a "strongly typed language", but it seems
- different from what's meant in C++. Are they different?
-
- (Tucker Taft responds)
-
- I certainly agree that ANSI C and C++ are statically typed languages,
- but I would debate the "strength" of their typing.
-
- Essentially any support for implicit conversion (implicit "casting,"
- "promotion", "usual" arithmetic conversions, etc.) "weakens" a type
- system (but also makes it "friendlier" in some ways).
-
- C allows implicit conversion between all integer types and all
- enumeration types. C++ at least cuts off implicit conversion to
- enumeration types, but retains implicit conversion among all integer
- (and floating-point) types. Also, in both C and C++, typedefs for
- pointer/array types are essentially "macros"; all pointer types with
- the same target type are implicitly interconvertible.
-
- Finally C++ allows the user to define a number of their own implicit
- conversion operators, which basically allows the user to "weaken" the
- type system as they see fit.
-
- Of course, all of this implicit conversion serves a purpose, but it
- does tend to move C/C++ toward the "weaker" end of the weak vs. strong
- typing spectrum.
-
- Note that the "strong" distinctions between integer types helps
- dramatically in catching (at compile-time) array indexing errors in
- Ada programs, by making sure that if you have an array indexed by a
- count of apples, you don't index into it with a count of oranges
- (without an *explicit* conversion). The advantages of "strongly"
- distinguishing enumeration types is even more obvious (and the
- designers of C++ recognized this).
-
- The strong distinctions between access types (pointer types) in Ada
- also has advantages, allowing access types to be represented as
- offsets within their storage pool rather than as addresses, and giving
- more high-level control over storage management.
-
- Strong typing can be carried too far, and some amount of implicit
- conversion is essential to make OOP palatable. But note that in Ada
- 9X, even with OOP, we don't allow implicit conversions that truncate
- the extension part of a record (this is a relatively common mistake in
- C++ when passing parameters by value). Instead, in Ada 9X, the
- language distinguishes between a specific type T and the class-wide
- type T'Class, and allows implicit conversions to T'Class from T or any
- of its derivatives, but not to the specific type T. Conversions to the
- class-wide type never implicitly truncate the extension part.
- Conversions to a specific type can truncate, and hence must be
- explicit.
-
- Note also that in Ada there are three distinct kinds of conversions,
- implicit ones, explicit ones, and unchecked ones. Only the unchecked
- ones are potentially unsafe. The explicit ones are safe, with either
- compile-time or run-time checks to ensure that. In C there are only
- implicit and explicit/unchecked conversions. C++ has recently added a
- checked, explicit "dynamic" cast, but still it will be common to use
- "normal" explicit casts for both checked and unchecked conversions,
- thereby making it more difficult to identify places where the type
- system might be compromised.
-
- Hence, the bottom line is that the type checking is (objectively)
- "stronger" in Ada than C/C++, though that doesn't necessarily mean
- "better" -- whether one is "better" for a particular style of
- programming than the other is a "religious" issue IMHO. I know my
- religion currently favors the stronger checking of Ada in most cases
- [except perhaps for multiply/divide, where I personally believe the
- checking should either be weaker, or directly support the concept of
- "units"/"dimensions"].
-
-
- 9.7: I'm told Ada does all sorts of static type checking, but can't you get
- the same effect using a tool like "lint" with C?
-
- No, here are a few reasons why (this list is by no means complete):
-
- (Submitted by Norm Cohen)
- * Running both Lint and a C compiler requires the program text to be
- parsed and semantically analyzed twice. The results of an Ada
- compiler's parse and semantic analysis are used directly in
- performing consistency checks.
-
- * The rules of Ada provide the opportunity for stronger consistency
- checks than are possible with C. For example, an Ada programmer
- can declare distinct integer types to represent distinct
- abstractions. An Ada compiler will catch an inadvertent
- intermixing of these two types, but there is no way a
- corresponding distinction can be made in C, so there is no way for
- Lint to perform a corresponding check. Similarly, in C, a pointer
- to an object of type T is indistinguishable from an array of
- objects of type T.
-
- * The rules of the Ada language ensure that the program text
- provides information allowing PRECISE consistency checks. For
- example, the expression in an Ada case statement can be written to
- have a static subtype, allowing the compiler to ascertain that all
- possible values have been covered without resorting to a default
- (when others) arm.
-
- * With lack of precise information, Lint has no choice but to be
- overly pessimistic or, with different settings for a complicated
- set of options, overly optimistic. When it is overly pessimistic,
- the user sees too many "false alarms" and may end up ignoring
- valid warnings. When it is overly optimistic, Lint overlooks
- certain errors.
-
- * It is impossible to forget to run consistency checks when using an
- Ada compiler. (Of course a C programming environment could be set
- up so that the C compiler could only be invoked from a script that
- also invokes Lint.)
-
- * A compilation that fails Ada consistency checks is rejected. A
- compilation that fails Lint consistency checks may still be
- compiled, and its object file used (intentionally or accidently)
- in building the system. (One cannot automate the rejection of
- programs that fail Lint unless one is certain that there will
- never be any false warnings.)
-
- * Ada enforces consistency among separately compiled units.
-
-
- Of course even stronger arguments can be made about Ada's RUN-TIME
- checks (which can be used with little additional overhead because the
- information contained in an Ada program and the knowledge that the
- program has passed compile-time consistency checks make it possible to
- optimize away the majority of the checks). These checks, which are
- absent in C, tend to smoke out errors early by detecting internal
- inconsistencies that might not otherwise be detected during testing.
- This reduces the likelihood of fielding a system that appears to work
- well during testing but fails in operational use.
-
-
- 9.8: Does Ada have something like the Standard Template Library (STL) in C++,
- or components like you find in Smalltalk environments?
-
- Yes, in various ways.
-
- Few components are part of the ISO standard. Ada 95 has an expanded
- set of predefined library units, covering e.g. strings of varying- or
- dynamic-length, elementary numerical functions, random number
- generators, complex numbers, and more; in addition, the Special Needs
- Annexes standardize many advanced services which have commonly been
- provided by separate components in the past.
-
- A lot of free Ada software components are available from anonymous FTP
- sites. There is also an upcoming release of the Booch Components for
- Ada 95 under the GNU Library General Public License (LGPL); this will
- give you the ability to freely include the library components in your
- application without any cost or obligation. (Contact
- dweller@neosoft.com for more details.)
-
- What about STL and the Smalltalk library?
-
- The C++ STL does not contain much. Breaking its source code down, it
- contains less than 3000 semicolons (~7000 total lines). The entire
- library exists in C++ header files as inlineable code (supposedly
- within a few percent of the efficiency of hand-optimized code).
-
- STL class hierarchy
-
- bool, heap -- of course Ada does not need a bool class!
- \ function, pair, stack
- \ iterator, tempbuf, projection
- \ algobase
- \ algorithms, bitvector, deque, list, tree, vector
- \ map, multimap, set, multiset
-
-
- The main author of the library, Alexander Stepanov, created the Ada
- Generic Library in the 1980's -- and later borrowed from this to
- create STL. (There is an interview with Stepanov in the March 1995
- issue of Dr. Dobb's Journal -- in the C Programming column beginning
- on page 115. Stepanov explains that these packages were first done in
- Ada.)
-
- The Smalltalk library is quite eclectic. It covers everything from
- Boolean to bitmaps, dictionaries and other collections. Parts of it
- have direct equivalents in Ada 95, parts are already available in
- components from anonymous FTP sites and/or will be in the Booch Ada 95
- components, and other parts are available from commercial Ada
- component suppliers.
-
-
- 9.9: Where can I find the equivalent of "printf" in Ada?
-
- While the standard package Text_IO provides many features, the
- request for a printf-like function is not unusual.
-
- (solution based on a suggestion by Tucker Taft)
-
- It is possible to produce a printf-like capability by overloading the
- "&" operator to take an object of type Format and an object of some
- type and return the Format, properly advanced, after having performed
- the appropriate output. The remaining format can be converted back to
- a string--e.g. to examine what is left at the end of the format
- string-- or simply printed to display whatever remains at the end. For
- example:
-
- with Text_IO;
- package Formatted_Output is
- type Format is
- limited private;
-
- function Fmt (Str : String)
- return Format;
-
- function "&" (Left : Format; Right : Integer)
- return Format;
- function "&" (Left : Format; Right : Float)
- return Format;
- function "&" (Left : Format; Right : String)
- return Format;
- ... -- other overloadings of "&"
-
- procedure Print (Fmt : Format);
-
- function To_String (Fmt : Format)
- return String;
-
- private
- ...
- end Formatted_Output;
-
- with Formatted_Output; use Formatted_Output;
- procedure Test is
- X, Y : Float;
- begin
- Print (Fmt("%d * %d = %d\n") & X & Y & X*Y);
- end Test;
-
- The private part and body of Formatted_Output are left as an exercise
- for the reader ;-).
-
- A "File : File_Type" parameter could be added to an overloading of Fmt
- if desired (to create something analogous to fprintf).
-
- This capability is analogous to that provided by the "<<" stream
- operator of C++.
-
- _________________________________________________________________
-
-
- 10: Interfacing with Ada
-
-
- 10.1: I am writing software that used the Distributed Interactive Simulation
- (DIS) interface, does an interface exist in Ada?
-
- Yes. DIS is a standard for communications between simulators using an
- Internet Protocol network (IP). DIS provides a unified virtual
- environment for multiple simulator users on a network. It is used
- mostly in the DoD simulations business, but it is applicable to ANY
- simulation. It is an industry initiative involving military training
- and procurement organisations, simulator vendors and universities
- mostly in the US, but the technology is unclassified.
-
- The Institute of Simulation and Training, URL
- http://www.tiig.ist.ucf.edu/ is a center at the University of Central
- Florida (UCF) which serves as the support contractor for the
- Simulation and Training Command (STRICOM). Current (published)
- standards can be found there, as are BBS's for the DIS working groups
- who are attempting to push those standards forward. The BBS contains
- an Ada binding for DIS.
-
- Note that the above provides a thin binding to C code. It may be
- worthwhile to take the time to make high level DIS bindings. Someone
- reports having done it in over 2 man-months using an experienced Ada
- engineer, and that it was well worth it. Many bugs were found in the C
- DIS code of the machine they were networked with. "A strongly-typed
- interface is the network programmer's best friend."
-
- At TRI-Ada'94 there was a demonstration by Coleman Research
- Corporation (CRC); here's their short pitch: "CRC presents Ada
- VR-Link, the first commercially available DIS NIV. It provides all of
- the facilities necessary to jump start your DIS compliant simulation
- development efforts. For more information call (205) 922-6000."
-
- Also, the AJPO sponsored an Ada Technology Insertion Program (ATIP)
- relating to this, FY93 ATIP project 17, titled "Ada Distributed
- Interactive Simulation (ADIS)". According to its charter, "The primary
- purpose of the ADIS project will be the creation of Ada interface
- bindings to allow an Ada simulation application to use the DIS
- protocols." As with any other AJPO-related work, contact the Ada
- Information Clearinghouse for more information.
-
- There are several sources of information available on DIS itself. The
- IEEE version of the DIS standard is available (and only available)
- through IEEE (IEEE standard number is ??). Draft versions of the
- standard are available from the Institute for Simulation and Training
- at the University of Central Florida. They take orders at (407)
- 855-0881, and questions (about ordering) at (407) 658-5054.
-
-
- 10.2: Is there any support for Common Object Request Broker Architecture
- (CORBA) for Ada 9X?
-
- (from Bill Beckwith, Bill.Beckwith@ois.com)
-
- Objective Interface Systems, Inc. (OIS), MITRE, and DISA have been
- working on a mapping from CORBA IDL to Ada 95 for about six months. I
- will send a recent copy of the mapping document to any interested
- parties. OC Systems, Rational, and OIS are planning on selling CORBA
- products for Ada.
-
- Note that CORBA IDL to Ada 95 mapping specifies a mapping, not a
- binding. This will put Ada 95 on equal footing with the C++ and
- Smalltalk products. (except, of course, the Ada mapping is cleaner ;-)
-
-
- _________________________________________________________________
-
-
- 11: Finding Additional Information
-
-
- 11.1: Where can I find Ada books?
-
- Try the comp.lang.ada FAQ, or the Ada WWW homepage
- (http://lglwww.epfl.ch/Ada/). Michael Feldman maintains the "Annotated
- Sampling of Ada-Oriented Textbooks", if you don't have access to WWW,
- drop him a note at mfeldman@seas.gwu.edu
-
-
- 11.2: Are there other Ada-related FAQs?
-
- Yes. They all appear in comp.lang.ada at regular intervals:
- comp.lang.ada FAQ, public Ada library FAQ, and Ada WWW server FAQ. All
- these are permanently available in hypertext format from the Ada WWW
- Server (see below) and in ASCII format from
- ftp://lglftp.epfl.ch/Ada/FAQ
-
-
- 11.3: What is the "Ada WWW Server"?
-
- The Ada WWW Server is alive and heavily used. It is a hypertext,
- multimedia information server for the Ada programming language.
-
- The URL of the Ada WWW Server is
-
- http://lglwww.epfl.ch/Ada/
-
- [don't forget the trailing '/'.]
-
- The Ada WWW Server provides Ada-related information and hypertext
- access in areas including:
- * Historical notes on Ada
- * References
- * Ada FAQs
- * State of Ada 9X revision process
- * Standards
- * Bindings
- * Tools and Components
- * Intellectual Ammunition
- * Introductory Material
- * Resources
- * CS Technical Reports
- * FTP and WWW Sites--including mirror sites
- * Calendar of Ada-related events
- * Ada Today
- * Frequently Asked Questions--with Answers (from comp.lang.ada)
-
-
- For instance, you will find a list of schools using Ada in CS1 or CS2,
- an article on commercial success stories, information about software
- components, as well as hypertext versions of the Ada reference manual
- (both 83 and draft 9X).
-
- The Ada WWW Server keeps growing. All comments, ideas, and requests
- for additions or corrections, are welcome (e-mail to
- Magnus.Kempe@di.epfl.ch).
-
- _________________________________________________________________
-
-
- 12: Pretty-printing Ada Source Code
-
-
- 12.1: Is there software that generates a pretty PostScript file from Ada
- source code?
-
- Pretty Ada code in PostScript means that e.g. reserved words are in
- bold and comments are in italics. This is a separate issue from
- re-formatting and automatic indenting.
-
- If you use the new Ada Mode for GNU Emacs (available from
- ftp://cs.nyu.edu/pub/gnat), go and get the package ps-print.el from
- any emacs archive (e.g. in directory
- ftp://archive.cis.ohio-state.edu/pub/gnu/emacs/elisp-archive). With
- this package you can print your code as you see it on the screen, say
- with bold keywords and italic comments.
-
- Another possibility is to feed the source to "vgrind" (see below),
- then pipe the result through "pscat" (to get PostScript) or "lpr -t"
- (to print), e.g.:
-
- vgrind -d <vgrind_defs_file> -lada -o1- -t -w $* | lpr -t
-
-
- 12.2: I use vgrind to do "pretty printing" of my source. Is there a vgrind
- definition for Ada?
-
-
- # Ada!
- ada|Ada:\
- :pb=(^\d?(procedure|function|package|package body))\d\p:\
- :bb=if|case|begin|loop:be=end:\
- :cb=--:ce=$:\
- :sb=":se=":\
- :lb=':le=':\
- :id=_.:\
- :oc:\
- :kw=abort abs abstract accept access aliased all and array at\
- begin body case constant declare delay delta digits do else\
- elsif end entry exception exit for function generic goto if in is\
- limited loop mod new not null of or others out package pragma\
- private procedure protected raise range record rem renames requeue\
- return reverse select separate subtype tagged task terminate then\
- type until use when while with xor:
-
-
- Note that the above has a problem with attributes, because the "lb"
- and "le" terms make two-attributes-20-lines-apart look like one
- "string literal." Ada 95 keywords are recognized.
-
- Here is another definition, which "fixes" this problem (not perfect,
- but probably better). Only Ada 83 keywords are recognized.
-
- # In order to get the ticks to work, we are assuming that there will be
- # whitespace before a literal (like '"') and *not* when used for an
- # attribute (like 'Length).
- # For sb/se, we are ALSO assuming that literals have whitespace before/after.
- Ada|ada:\
- :pb=^\d?(procedure|function|package|package\dbody)\d\p:\
- :bb=begin:be=end:\
- :cb=--:ce=$:\
- :sb=( |\t|\()":se="( |\t|;|,|\)):\
- :lb=(>| |\t)':le='(\)| |\t|;):\
- :tl:\
- :oc:\
- :kw=abort abs accept access all and array at begin body case constant\
- declare delay delta digits do else elsif end entry exception exit for\
- function generic goto if in is limited loop mod new not null of or\
- others out package pragma private procedure raise range record rem\
- renames return reverse select separate subtype task terminate then\
- type use when while with xor:
-
-
- 12.3: How about a source code reformatter?
-
- If you can run a Perl script (Perl is freely available for almost
- every OS in the world), you can use the program aimap, written by Tom
- Quiggle of SGI. It can be found (where ???).
-
- _________________________________________________________________
-
-
- 13: Common Confusions
-
-
- 13.1: Wasn't Ada designed by some committee? What kind of a language could you
- possibly get from that kind of approach?
-
- (Tucker Taft, the principal designer of Ada 95, responds)
-
- I believe most reviewers of Ada 9X (and Ada 83 for that matter) will
- assure you that it was most certainly not designed by committee ;-).
-
- In fact, with respect to MI, the situation was just the opposite.
- There were several reviewers who pushed hard for building in a
- particular approach to MI. The principle designer (;-) was unconvinced
- that the benefits of building in a particular MI approach outweighed
- the costs as far as complexity. There was no clear winner to use as a
- model in the outside world; even Sather and Eiffel couldn't agree
- exactly on how to resolve the intricacies of MI, despite their strong
- similarities in other areas.
-
-
- 13.2: I've heard the DoD is dropping all Military standards to reduce costs,
- doesn't that mean the mandate to use Ada goes away too?
-
- The following memo explains how that decision affects the Ada
- mandate:
-
- OFFICE OF THE SECRETARY OF DEFENSE
-
- Washington, DC 20301-1000
-
- August 26, 1994
-
-
- MEMORANDUM FOR SECRETARIES OF THE MILITARY DEPARTMENTS
- CHAIRMAN OF THE JOINT CHIEFS OF STAFF
- UNDER SECRETARY OF DEFENSE (PERSONNEL AND
- READINESS)
- UNDER SECRETARY OF DEFENSE (POLICY)
- COMPTROLLER OF THE DEPARTMENT OF DEFENSE
- GENERAL COUNSEL OF THE DEPARTMENT OF DEFENSE
- INSPECTOR GENERAL OF THE DEPARTMENT OF DEFENSE
- DIRECTOR OF OPERATIONAL TEST AND EVALUATION
- DIRECTORS OF THE DEFENSE AGENCIES
-
- SUBJECT: Use of Ada
-
- The purpose of this memorandum is to reiterate the Department
- of Defense (DoD) commitment to the use of Ada.
-
- It is DoD policy to use commercial off-the-shelf (COTS)
- software whenever it meets our requirements. However, when COTS
- software is not available to satisfy requirements and the DoD must
- develop unique software to meet its needs, that software must be
- written in the Ada programming language in accordance with DoD
- Directive 3405.1 and DoD Instruction 5000.2.
-
- Secretary Perry's June 29, 1994 memorandum, "Specification &
- Standards -- A New Way of Doing Business," states that military
- standards will only be used "as a last resort, with an appropriate
- waiver." This direction has caused some confusion regarding the
- Ada requirement since most references to Ada cite its MIL-STD
- nomenclature, MIL-STD-1815A. Ada is also a Federal Information
- Processing Standard (FIPS 119), an American National Standards
- Institute (ANSI) standard (ANSI-1815A-1983), and an International
- Standards Organization (ISO) standard (ISO 8652-1987). Any of
- these alternative references may be utilized in place of the MIL-
- STD reference in request for proposals, contracts, and other
- similar documents. Thus, the Ada requirement does not conflict
- with the Secretary's direction, and compliance with both policies
- can be achieved simultaneously.
-
- Use of other programming languages can be considered if
- proposed by a contractor as part of his best practices since
- waivers to the use of Ada can be granted, where cost-effective, in
- accordance with procedures established in the policy referenced
- above. However, such proposals require strong justification to
- prove that the overall life-cycle cost will be less than the use of
- Ada will provide.
-
- Secretary Perry's memorandum encourages practices that satisfy
- the Department's need to build high quality systems that meet
- requirements at affordable costs an in a timely manner. This
- includes practices which support the development of Defense
- Software. Ada is not only a facilitator of software engineering
- best practice, but also has inherent features which uniquely
- support both real-time systems and safety-critical systems. Use of
- Ada also facilitates software reuse and has demonstrated reduced
- support costs. Accordingly, Ada is a foundation for sound software
- engineering practice.
-
- /signed/ /signed/
-
- Noel Longuemare Emmett Paige, Jr.
- Under Secretary of Defense Assistant Secretary of Defense
- (Acquisition and Technology) (Command, Control,
- (Acting) Communications, and
- Intelligence)
-
- cc:
- DDR&E
-
-
- _________________________________________________________________
-
-
- 14: Credits
-
- The following persons have contributed (directly or indirectly,
- intentionally or unintentionally, through e.g. comp.lang.ada) to the
- information gathered in this FAQ: TuckeráTaft, DaveáWeller,
- BilláBeckwith, ChipáBennett, BevináBrett, NormáCohen,
- TheodoreáE.áDennison, RobertáDewar, BobáDuff, RobertáEachus,
- RolfáEbert, LaurentáGuerby, JeffreyáL.áGrover, RichardáG.áHash,
- JobáHonig, JeanáD.áIchbiah, NasseráKettani, WayneáR.áLawton,
- RobertáMartin, RobbáNebbe, JonathanáParker, IsaacáPentinmaki,
- BruceáPetrick, PauláPukite, RichardáRiehle, DavidáShochat,
- JoyceáTokar, FraseráWilson, and the maintainer has simply :-)
- organized, polished, or added some information for your satisfaction.
- The general HTML structure of this FAQ was inspired by the WWW FAQ.
-
- _________________________________________________________________
-
-
- 15: Copying this FAQ
-
- This FAQ is Copyright 1994, 1995 by Magnus Kempe. It may be freely
- redistributed as long as it is completely unmodified and that no
- attempt is made to restrict any recipient from redistributing it on
- the same terms. It may not be sold or incorporated into commercial
- documents without the explicit written permission of the copyright
- holder.
-
- Permission is granted for this document to be made available under the
- same conditions for file transfer from sites offering unrestricted
- file transfer on the Internet and from Forums on e.g. Compuserve and
- Bix.
-
- This document is provided as is, without any warranty.
-
-