7.5 Limited Types
[A limited type is (a view of) a type for which copying (such as for
is not allowed. A nonlimited type is a (view of a) type for which copying
Discussion: The concept of the value
of a limited type is difficult to define, since the abstract value of
a limited type often extends beyond its physical representation. In some
sense, values of a limited type cannot be divorced from their object.
The value is the object.
In Ada 83, in the two places where limited types were defined by the
language, namely tasks and files, an implicit level of indirection was
implied by the semantics to avoid the separation of the value from an
associated object. In Ada 95, most limited types are passed by reference,
and even return-ed by reference. In Ada 2005, most limited types are
built-in-place upon return, rather than returned by reference. Thus the
object “identity” is part of the logical value of most limited
To be honest:
For a limited partial view whose full view is nonlimited, copying is
possible on parameter passing and function return. To prevent any copying
whatsoever, one should make both the partial and
full views limited.
A limited type is a type
for which copying (such as in an assignment_statement
is not allowed. A nonlimited type is a type for which copying is allowed.
If a tagged record type has any limited components, then the reserved
shall appear in its record_type_definition
[If the reserved word limited
appears in the definition of a derived_type_definition
its parent type and any progenitor interfaces shall be limited.]
The rule about the parent type being required to be limited can be found
. Rules about progenitor interfaces can
be found in 3.9.4;,
specifically, a nonlimited interface can appear only on a nonlimited
type. We repeat these rules here to gather these scattered rules in one
prevents tagged limited types from becoming nonlimited. Otherwise, the
following could happen:
package P is
type T is limited private;
type R is tagged
record -- Illegal!
-- This should say “limited record”.
X : T;
type T is new Integer; -- R becomes nonlimited here.
package Q is
type R2 is new R with
Y : Some_Task_Type;
If the above were legal, then assignment would be defined for R'Class
in the body of P, which is bad news, given the task.
Discussion: All of these contexts normally
require copying; by restricting the uses as above, we can require the
new object to be built-in-place.
Ramification: Note that there is always
a “definition,” conceptually, even if there is no syntactic
category called “..._definition”.
This includes interfaces of the above kinds, derived types with the reserved
, as well as task and protected types.
a derived type whose parent is limited and is not an interface.
Limitedness is not inherited from interfaces; it must be explicitly specified
when the parent is an interface.
To be honest:
A derived type can become nonlimited if limited
does not appear
and the derivation takes place in the visible part of a child package,
and the parent type is nonlimited as viewed from the private part or
body of the child package.
We considered a rule where limitedness was always inherited from the
parent for derived types, but in the case of a type whose parent is an
interface, this meant that the first interface is treated differently
than other interfaces. It also would have forced users to declare dummy
nonlimited interfaces just to get the limitedness right. We also considered
a syntax like not limited
to specify nonlimitedness when the parent
was limited, but that was unsavory. The rule given is more uniform and
simpler to understand.
The rules for interfaces are asymmetrical, but the language is not: if
the parent interface is limited, the presence of the word limited
determines the limitedness, and nonlimited progenitors are illegal by
the rules in 3.9.4
If the parent interface is nonlimited, the word limited
by the rules in 3.4
. The net effect is that
the order of the interfaces doesn't matter.
Otherwise, the type is nonlimited.
[There are no predefined equality operators for a
A type is immutably limited
if it is one of the following:
An explicitly limited record type;
A record extension with the reserved word limited
A nonformal limited private type that is tagged
or has at least one access discriminant with a default_expression
Reason: The full type in both of these
cases must necessarily be immutably limited. We need to include private
types as much as possible so that we aren't unintentionally discouraging
the use of private types.
A task type, a protected type, or a synchronized
A type derived from an immutably limited type.
Discussion: An immutably limited type
is a type that cannot become nonlimited subsequently in a private part
or in a child unit. If a view of the type makes it immutably limited,
then no copying (assignment) operations are ever available for objects
of the type. This allows other properties; for instance, it is safe for
such objects to have access discriminants that have defaults or designate
other limited objects.
Ramification: A nonsynchronized limited
interface type is not immutably limited; a type derived from it can be
A descendant of a generic formal limited private type is presumed to
be immutably limited except within the body of a generic unit or a body
declared within the declarative region of a generic unit, if the formal
type is declared within the formal part of the generic unit.
Ramification: In an instance, a type
is descended from the actual type corresponding to the formal, and all
rules are rechecked in the specification. Bodies are excepted so that
we assume the worst there; the complex wording is required to handle
children of generics and unrelated bodies properly.
To be honest:
This isn't quite true if
the type can become nonlimited (see below); function_call
only are required to be build-in-place for “really” limited
Paragraphs 10 through
15 were deleted.
illustrated in 7.3.1
, an untagged limited
type can become nonlimited under certain circumstances.
Ramification: Limited private types do
not become nonlimited; instead, their full view can be nonlimited, which
has a similar effect.
It is important to remember that a single nonprivate
type can be both limited and nonlimited in different parts of its scope.
In other words, “limited” is a property that depends on where
you are in the scope of the type. We don't call this a “view property”
because there is no particular declaration to declare the nonlimited
Tagged types never become nonlimited.
Example of a package
with a limited type:
package IO_Package is
type File_Name is limited private;
procedure Open (F : in out File_Name);
procedure Close(F : in out File_Name);
procedure Read (F : in File_Name; Item : out Integer);
procedure Write(F : in File_Name; Item : in Integer);
type File_Name is
Internal_Name : Integer := 0;
package body IO_Package is
Limit : constant := 200;
type File_Descriptor is record ... end record;
Directory : array (1 .. Limit) of File_Descriptor;
procedure Open (F : in out File_Name) is ... end;
procedure Close(F : in out File_Name) is ... end;
procedure Read (F : in File_Name; Item : out Integer) is ... end;
procedure Write(F : in File_Name; Item : in Integer) is ... end;
19 Notes on the example: In the
example above, an outside subprogram making use of IO_Package may obtain
a file name by calling Open and later use it in calls to Read and Write.
Thus, outside the package, a file name obtained from Open acts as a kind
of password; its internal properties (such as containing a numeric value)
are not known and no other operations (such as addition or comparison
of internal names) can be performed on a file name. Most importantly,
clients of the package cannot make copies of objects of type File_Name.
This example is characteristic of any case where complete
control over the operations of a type is desired. Such packages serve
a dual purpose. They prevent a user from making use of the internal structure
of the type. They also implement the notion of an encapsulated data type
where the only operations on the type are those given in the package
The fact that the full view of File_Name is explicitly declared limited
means that parameter passing will always be by reference and function
results will always be built directly in the result object (see 6.2
Extensions to Ada 83
The restrictions in RM83-7.4.4(4),
which disallowed out
parameters of limited types in certain cases,
Wording Changes from Ada 83
Extensions to Ada 95
Wording Changes from Ada 95
Rewrote the definition of limited to ensure that interfaces are covered,
but that limitedness is not inherited from interfaces. Derived types
that explicitly include limited
are now also covered.
Wording Changes from Ada 2005
Added a definition for immutably limited types, so
that the fairly complex definition does not need to be repeated in rules
elsewhere in the Standard.
The built-in-place rules are consolidated in 7.6
and thus they are removed from this subclause.
Fixed an oversight: class-wide types were never defined
to be limited, even if their associated specific type is. It is thought
that this oversight was never implemented incorrectly by any compiler,
thus we have not classified it as an incompatibility.
Added wording so that expression functions can return limited entities.
Added incomplete views to the list of reasons for
a view of a type to be limited. This is not a change as the definition
already was in 3.10.1
. But it is much better
to have all of the reasons for limitedness together.
Extensions to Ada 2012
Correction: A raise_expression
can be used in an expression used in a limited context. This is harmless
(no object will be created if an exception is raised instead), useful,
and thus appears to have been an omission when raise_expressions
were added to the language.
Wording Changes from Ada 2012
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe