Rationale for Ada 2005

John Barnes
Contents   Index   References   Search   Previous   Next 

9.1.1 Incompatibilities with Ada 95

Each incompatibility listed below gives the AI concerned and the paragraph in the AARM which in some cases will give more information. Where relevant, the section in this rationale where the topic is discussed is also given. Where appropriate the incompatibilities are grouped together.
1 — The words interface, overriding and synchronized are now reserved. Programs using them as identifiers will need to be changed. (AI-284, 2.9(3.c))
This is perhaps the most important incompatibility in terms of visibility to the average programmer. It is discussed in 2.2.
2 — If a predefined package has additional entities then incompatibilities can arise. Thus suppose the predefined package Ada.Stuff has an additional entity More added to it. Then if an Ada 95 program has a package P containing an entity More then a program with a use clause for both Ada.Stuff and P will become illegal in Ada 2005 because the reference to More will become ambiguous. This also applies if further overloadings of an existing entity are added.
Because of this there has been reluctance to extend existing packages but a preference to add child packages. Nevertheless in some cases extending a package seemed more appropriate especially if the identifiers concerned are unlikely to have been used by programmers.
The following packages have been extended with additional entities as listed.
Ada.ExceptionsWide_Exception_Name, Wide_Wide_Exception_Name. (AI-400, 11.4.1(19.bb))
Ada.Real_TimeSeconds, Minutes. (AI-386, D.8(51.a))
Ada.StringsWide_Wide_Space. (AI-285, A.4.1(6.a))
Ada.Strings.FixedIndex, Index_Non_Blank. (AI-301, A.4.3(109.a))
Ada.Strings.BoundedSet_Bounded_String, Bounded_Slice, Index, Index_Non_Blank. (AI-301, A.4.4(106.f))
Ada.Strings.UnboundedSet_Unbounded_String, Unbounded_Slice, Index, Index_Non_Blank. (AI-301, A.4.5(88.c))
There are similar additions to Ada.Strings.Wide_Fixed, Ada.Strings.Wide_Bounded and Ada.Strings.Wide_Unbounded. (AI-301, A.4.7(48.a))
Ada.TagsNo_Tag, Parent_Tag, Interface_Ancestor_Tags, Descendant_Tag, Is_Descendant_ At_Same_Level, Wide_Expanded_Name, Wide_Wide_Expanded_Name. (AI-260, AI-344, AI-400, AI-405, 3.9(33.d))
Ada.Text_IOGet_Line. (AI-301, A.10.7(26.a))
Interfaces.Cchar16_t, char32_t and related types and operations. (AI-285, B.3(84.a))
It seems unlikely that existing programs will be affected by these potential incompatibilities.
3 — If a subprogram has an access parameter (without a null exclusion) and is not a dispatching operation then it cannot be renamed as a dispatching operation in Ada 2005 although it can be so renamed in Ada 95. See 3.2 for an example. (AI-404, 3.9.2(24.b))
4 — As discussed in 3.5, there are many awkward situations in Ada 95 regarding access types, discriminants and constraints. One problem is that some components can change shape or disappear. The rules in Ada generally aim to prevent such components from being accessed or renamed. However, in Ada 95, some entities don't look constrained but actually are constrained. The consequence is that it is difficult to prevent some constrained objects from having their constraints changed and this can cause components to change or disappear even though they might be accessed or renamed.
A key rule in Ada 95 was that aliased variables were always constrained with the intent that that would solve the problems. But loopholes remained and so the rules have been changed considerably. Aliased variables are not necessarily constrained in Ada 2005 and other rules now disallow certain constructions that were permitted in Ada 95 and this gives rise to a number of minor incompatibilities.
If a general access subtype refers to a type with default discriminants then that access subtype cannot have constraints in Ada 2005. Consider 
type T(Disc: Boolean := False) is
   end record;
The discriminated type T has a default and so unconstrained objects of type T are mutable. Suppose we now have
type T_Ptr is access all T;
subtype Sub_True_T_Ptr is T_Ptr(Disc => True);    -- subtype illegal in Ada 2005
The type T_Ptr is legal in both Ada 95 and Ada 2005 of course, but the subtype Sub_True_T_Ptr is only legal in Ada 95 and not in Ada 2005. The reason why the subtype cannot be permitted is illustrated by the following 
Some_T: aliased T := (Disc => True, ...);
A_True_T: Sub_True_T_Ptr := Some_T'Access;
Some_T := (Disc => False, ...);
When Some_T'Access is evaluated there is a check that the discriminant has the correct value so that A_True_T is assigned a valid value. But the second assignment to Some_T means that the discriminant changes and so A_True_T would no longer have a valid value.
In Ada 95, all aliased variables were considered constrained and so the second assignment would not have been permitted anyway. But, as mentioned above, aliased variables are not considered to be constrained in Ada 2005 just because they are aliased.
Note that there is no similar restriction on types; thus we can still write 
type True_T_Ptr is access all T(Disc => True);
because any conversion which might cause difficulties is forbidden as explained in one of the examples below.
The restriction on subtypes does not apply if the discriminants do not have defaults, nor to pool-specific types. (AI-363, 3.7.1(15.c))
Since aliased variables are not necessarily constrained in Ada 2005 there are situations where components might change shape or disappear in Ada 2005 that could not happen in Ada 95. Applying the Access attribute to such components is thus illegal in Ada 2005. Suppose the example above has components as follows 
type T(Disc: Boolean := False) is
      case Disc is
         when False =>
            Comp: aliased Integer;
         when True =>
      end case;
   end record;
Since objects of type T might be mutable, the component Comp might disappear.
type Int_Ptr is access all Integer;
Obj: aliased T;    -- mutable object
Dodgy: Int_Ptr := Obj.Comp'Access;    -- take care
Obj:= (Disc => True);    -- Comp gone
In Ada 95, the assignment to Dodgy is permitted but then the assignment to Obj raises Constraint_Error because there might be dodgy pointers.
In Ada 2005, the assignment statement to Dodgy is illegal since we cannot write Obj.Comp'Access. The assignment to Obj is itself permitted because we now know that there cannot be any dodgy pointers.
See (AI-363, 3.10.2(41.b)). Similarly, renaming an aliased component such as Comp is also illegal. (AI-363, 8.5.1(8.b))
There are related situations regarding discriminated private types where type conversions and the Access attribute are forbidden. Suppose we have a private type and an access type and that the full type is in fact the discriminated type above thus 
package P is
   type T is private;
   type T_Ptr is access all T;
   function Evil return T_Ptr;
   function Flip(Obj: T) return T;
   type T(Disc: Boolean := False) is
      end record;
end P;
package body P is
   type True_T_Ptr is access all T(Disc => True);
   subtype Sub_True_T_Ptr is T_Ptr(Disc => True);  --legal in Ada 95, illegal in Ada 2005
   True_Obj: aliased T(Disc => True);
   TTP: True_T_Ptr := True_Obj'Access;
   STTP: Sub_True_T_Ptr := True_Obj'Access;
   function Evil return T_Ptr is
      if ... then
         return T_Ptr(TTP);    -- OK in 95, not in Ada 2005
      elsif ... then
         return True_Obj'Access;    -- OK in 95, not in Ada 2005
        return STTP;
      end if;
   end Evil;
   function Flip(Obj: T) return T is
      case Obj.Disc is
         when True => return (Disc => False, ...);
         when False => return (Disc => True, ...);
      end case;
   end Flip;
end P;
The function Evil has three branches illustrating various possible ways of returning a value of the type T. The function Flip just returns a value of the type T with opposite discriminants to the parameter. Now consider 
with P;  use P;
procedure Do_It is
   A: T;
   B: T_Ptr := new T;
   C: T_Ptr := Evil;
   A := Flip(A);
   B.all := Flip(B.all);
   C.all := Flip(C.all);
end Do_It;
This declares an object A of type T and then two objects B and C of the access type T_Ptr and initializes them in different ways. Finally it attempts to change the discriminant of the three objects by calling the function Flip.
In Ada 95 all objects on the heap are constrained. This means that clients cannot change the discriminants even if they do not know that they exist. So the assignment to B.all raises Constraint_Error since B.all is on the heap and thus constrained whereas the assignment to A is fine since A is not constrained. However, from the client's point of view they both really do the same thing and so the behaviour is very curious. Remember that the client doesn't know about the discriminants and so both operations look the same in the abstract. This is unfortunate and breaks privacy which is sinful. There is a similar example in 3.5 where we try to change Chris but do not know that the new value has a beard and this fails because Chris is female.
To prevent such privacy breaking the rules are changed in Ada 2005 so that objects on the heap are unconstrained in this one case. So the assignments to B.all and C.all do not have checks on the discriminant. As a consequence Evil must not return an object which is constrained otherwise the assignment to C would result in True_Obj having its discriminant turned to False.
All three possible branches in Evil are prevented in Ada 2005. The conversion in the first branch is forbidden and the Access attribute in the second branch is forbidden. In the case of the third branch the return itself is acceptable in principle because STTP is of the correct type. However, this is prevented by the rule mentioned above since the subtype Sub_True_T_Ptr is itself forbidden and so the object STTP could not be declared in the first place.
See (AI-363, 3.10.2(41.e) and 4.6(71.k)).
5 — Aggregates of limited types are permitted in Ada 2005 as discussed in 4.5. This means that in obscure situations an aggregate might be ambiguous in Ada 2005 and thus illegal. Consider 
type Lim is limited
      Comp: Integer;
   end record;
type Not_Lim is
      Comp: Integer;
   end record;
procedure P(X: LIm);
procedure P(X: Not_Lim);
P((Comp => 123));    -- illegal in Ada 2005
In Ada 95, the aggregate cannot be of a limited type and so the type Lim is not considered for resolution. But Ada 2005 permits aggregates of limited types and so the aggregate is ambiguous. See (AI-287, 4.3(6.e))
Another similar situation with limited types and nonlimited types concerns assignment. Again this relates to the fact that limitedness is no longer considered for name resolution. Consider 
type Acc_Not_Lim is access Not_Lim;
function F(X: Integer) return Acc_Not_Lim;
type Acc_Lim is access Lim;
function F(X: Integer) return Acc_Lim;
F(1).all := F(2).all;    -- illegal in Ada 2005
In Ada 95, only the first F is considered for name resolution and the program is valid. In Ada 2005, there is an ambiguity because both functions are considered. Note of course that the assignment for the limited function is still illegal anyway but the compiler meets the ambiguity first. Clearly this is an obscure situation. (AI-287, 5.2(28.d))
6 — Because of the changes to the fixed-fixed multiplication and division rules there are situations where a legal program in Ada 95 becomes illegal in Ada 2005. Consider 
package P is
   type My_Fixed is delta ... ;
   function "*" (L, R: My_Fixed) return My_Fixed;
end P;
use P;
A, B: My_Fixed;
D: Duration := A * B;    -- illegal in Ada 2005
Although this is legal in Ada 95, the new rule in Ada 2005 says that if there is a user-defined operation involving the type concerned then the predefined operation cannot be used unless there is a type conversion or we write Standard."*"( ... ).
So in Ada 2005 a conversion can be used thus 
D: Duration := Duration(A * B);
See 6.3. (AI-364, 4.5.5(35.d))
7 — The concept of return by reference types has gone. Instead the user has to explicitly declare a function with an anonymous access type as the return type. This only affects functions that return an existing limited object such as choosing a task from among a pool of tasks. See 4.5 for an example. (AI-318, 6.5(27.g))
8 — There is a very curious situation regarding exporting multiple homographs from an instantiation that is now illegal. This is a side effect of adding interfaces to the language. (AI-251, 8.3(29.s))
9 — The introduction of more forms of access types has changed the rules regarding name resolution. Consider the following contrived example 
type Cacc is access constant Integer;
procedure Proc(Acc: access Integer);
procedure Proc(Acc: Cacc);
List: Cacc := ... ;
Proc(List);    -- illegal in Ada 2005
In Ada 95 the call of Proc is resolved because the parameters Acc are anonymous access to variable in one case and access to constant in the other. In Ada 2005, the name resolution rules do not take this into account so it becomes ambiguous and thus illegal which is a good thing because it is likely that the Ada 95 programmer made a mistake anyway. (AI-409, 8.6(34.n))
10 — In Ada 2005, a procedure call that might be an entry is permitted in timed and conditional entry calls. See 5.3. In Ada 95, a procedure could not be so used and this fact is used in name resolution in Ada 95 but does not apply in Ada 2005. Hence if a procedure and an entry have the same profile then an ambiguity can exist in Ada 2005. (AI-345, 9.7.2(7.b))
11 — It is now illegal to have an allocator for an access type with Storage_Size equal to zero whereas in Ada 95 it raised Storage_Error on execution. It is always better to detect errors at compile time wherever possible. The reason for the change is to allow Pure units to use access types provided they do not use allocators. If the storage size is zero then this is now known at compile time. (AI-366, 4.8(20.g))
12 — The requirement that a partial view with available stream attributes be externally streamable can cause an incompatibility in extremely rare cases. This incompatibility only applies to units with pragma Pure. (AI-366, 10.2.1(28.e))
13 — It is now illegal to use an incomplete view as a parameter or result of an access to subprogram type or as an access parameter of a primitive operation if the completion is deferred to the package body. See 4.2 for examples. (AI-326, 3.10.1(23.h, i))
14 — The specification of System.RPC can now be tailored for an implementation by adding further operations or by changing the profile of existing operations. If it is tailored in this way then an existing program might not compile in Ada 2005. See 7.7. (AI-273, E.5(30.a))

Contents   Index   References   Search   Previous   Next 
© 2005, 2006, 2007 John Barnes Informatics.
Sponsored in part by:
The Ada Resource Association and its member companies: ARA Members AdaCore Polyspace Technologies Praxis Critical Systems IBM Rational Sofcheck and   Ada-Europe: