Gem #46: Incompatibilities between Ada 83 and Ada 95
by Robert Dewar —AdaCore
Let's get started…
For the most part, Ada 95 is entirely upwards compatible with Ada 83, meaning that correctly written portable Ada 83 code can be compiled with an Ada 95 compiler, and no changes are required.
However, there are some cases of incompatibilities which have to be addressed when dealing with legacy code. You can of course compile in Ada 83 mode using the pragma Ada_83, or the equivalent compiler switch -gnat83 (/83 if you are using VMS). However, this means you can't use any Ada 95 features as you continue development, so it is better to fix these incompatibilities if possible.
In this series of Gems we will address these incompatibilities. Some are really easy, others trickier. In this first installment, we address one of the most common cases.
Consider the following declaration,
generic type T is private; package GP is ... end GP;
In Ada 83 you could instantiate this generic with an unconstrained type, for example:
package NP is new GP (String);
This is no longer allowed in Ada 95, since this represents a so-called "contract-model violation". If you try to compile the instantiation in Ada 95 mode, you will get an error:
8. package NP is new GP (String); | >>> actual for "T" must be a definite subtype
String is an indefinite subtype, meaning basically that it is unconstrained. In contrast, a definite subtype means a subtype whose bounds are constrained, so something like
subtype S50 is String (1 .. 50); package NP is new GP (S50);
would be legal, but unconstrained String cannot be used.
The contract model for generics says that if a generic compiles error free, then all possible instantiations must compile error free. But if you allow the above instantiation, then whether this is legal or not depends on whether the generic has a declaration of a variable of type T. If it does, then the instantiation is illegal, since you can't have variables of type String without specified bounds.
Let's assume that we don't have any illegal instantiations in the legacy code. That means that, in a case like the above, in fact there are no declarations of variables of type T. In that case, all you have to do is to change the generic as follows:
generic type T(<>) is private; package GP is ... end GP;
The use of (<>) here means that instantiation with an unconstrained subtype is allowed, and consequently the generic will check to ensure that no variables of type T are declared in the template, as you can see from this example:
1. generic 2. type T (<>) is private; 3. package GP is 4. Var : T; | >>> unconstrained subtype not allowed (need initialization) 5. end;
So, following the Ada 95 rules, the contract-model violation is now avoided. Either the generic allows unconstrained subtypes or it does not, and the generic is properly checked when it is compiled.
In summary, we do have a real incompatibility between Ada 83 and Ada 95 here, but it fixes a real hole in the language, and it is easy to fix up old Ada 83 code to meet the new Ada 95 rules.