Rationale for Ada 2005
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.Strings.Bounded —
Set_Bounded_String,
Bounded_Slice,
Index,
Index_Non_Blank.
(
AI-301,
A.4.4(106.f))
Ada.Strings.Unbounded
—
Set_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.Tags —
No_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))
Interfaces.C —
char16_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
record
...
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
record
case Disc is
when False =>
Comp: aliased Integer;
when True =>
null;
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.
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;
private
type T(Disc: Boolean := False) is
record
...
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
begin
if ... then
return T_Ptr(TTP); -- OK in 95, not in 2005
elsif ... then
return True_Obj'Access; -- OK in 95, not in 2005
else
return STTP;
end if;
end Evil;
function Flip(Obj: T) return T is
begin
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;
begin
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.
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
record
Comp: Integer;
end record;
type Not_Lim is
record
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);
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 also relates to 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))
© 2005, 2006 John Barnes Informatics.
Sponsored in part by: