Ada Programming/Types/limited
Limited Types
editWhen a type is declared limited
this means that objects of
the type cannot be assigned values of the same type.
An Object b of limited type LT cannot be copied into an object
a of same type LT.
Additionally, there is no predefined equality operation for objects of a limited type.
The desired effects of declaring a type limited include prevention of shallow copying. Also, the (unique) identity of an object is retained: once declared, a name of a variable of type LT will continue to refer to the same object.
The following example will use a rather simplifying type Boat.
type
Boatis
limited
private
;function
Choose (Load : Sailors_Units; Speed : Sailors_Units)return
Boat;procedure
Set_Sail (The_Boat :in
out
Boat);
When we declare a variable to be of type Boat, its name will denote one boat from then on. Boats will not be copied into one another.
The full view of a boat might be implemented as a record such as
type
Boatis
limited
record
Max_Sail_Area : Sailors_Units; Max_Freight : Sailors_Units; Sail_Area : Sailors_Units; Freight : Sailors_Units;end
record
;
The Choose function returns a Boat object depending on the parameters Load and Speed. If we now declare a variable of type Boat we will be better off Choosing an initial Boat (or else we might be dropping into uninitialized waters!). But when we do so, the initialization looks suspiciously like assignment which is not available with limited types:
procedure
Travel (People : Positive; Average_Speed : Sailors_Units)is
Henrietta : Boat := -- assignment? Choose (Load => People * Average_Weight * 1.5, Speed => Average_Speed * 1.5);begin
Set_Sail (Henrietta);end
Travel;
Fortunately, current Ada distinguishes initialization from copying. Objects of a limited type may be initialized by an initialization expression on the right of the delimiter :=.
(Just to prevent confusion: The Ada Reference Manual discriminates between assignment and assignment statement, where assignment is part of the assignment statement. An initialisation is of course an assignment which, for limited types, is done in place. An assignment statement involves copying, which is forbidden for limited types.)
Related to this feature are aggregates of limited types and “constructor functions” for limited types. Internally, the implementation of the Choose function will return a limited record. However, since the return type Boat is limited, there must be no copying anywhere. Will this work? A first attempt might be to declare a result variable local to Choose, manipulate result, and return it. The result object needs to be “transported” into the calling environment. But result is a variable local to Choose. When Choose returns, result will no longer be in scope. Therefore it looks like result must be copied but this is not permitted for limited types. There are two solutions provided by the language: extended return statements (see 6.5: Return Statements [Annotated]) and aggregates of limited types. The following body of Choose returns an aggregate of limited type Boat, after finding the initial values for its components.
function
Choose (Load : Sailors_Units; Speed : Sailors_Units)return
Boatis
Capacity :constant
Sailors_Units := Capacity_Needed (Load);begin
return
Boat' (Max_Freight => Capacity, Max_Sail_Area => Sail_Needed (Capacity), Freight => Load, Sail_Area => 0.0);end
Choose;
The object that is returned is at the same time the object that is to have the returned value. The function therefore initializes Henrietta in place.
In parallel to the predefined type Ada.Finalization.Controlled, Ada provides the type Limited_Controlled in the same package. It is a limited version of the former.
Initialising Limited Types
editA few methods to initialise such types are presented.
package
Limited_Private_Samplesis
type
Uninitialisedis
limited
private
;type
Preinitialisedis
limited
private
;type
Dynamic_Initialisationis
limited
private
;function
Constructor (X: Integer) -- any kind of parametersreturn
Dynamic_Initialisation;type
Needs_Constructor (<>)is
limited
private
;function
Constructor (X: Integer) -- any kind of parametersreturn
Needs_Constructor;private
type
Uninitialisedis
record
I: Integer;end
record
;type
Preinitialisedis
record
I: Integer := 0; -- can also be a function callend
record
;type
Voidis
null
record
;function
Constructor (Object:access
Dynamic_Initialisation)return
Void;type
Dynamic_Initialisationis
limited
record
Hook: Void := Constructor (Dynamic_Initialisation'Access
); Bla : Integer; -- any needed componentsend
record
;type
Needs_Constructoris
record
I: Integer;end
record
;end
Limited_Private_Samples;
package
body
Limited_Private_Samplesis
function
Constructor (Object:access
Dynamic_Initialisation)return
Voidis
begin
Object.Bla := 5; -- may be any value only known at run timereturn
(null
record
);end
Constructor;function
Constructor (X: Integer)return
Dynamic_Initialisationis
begin
return
(Hook => (null
record
), Bla => 42);end
Constructor;function
Constructor (X: Integer)return
Needs_Constructoris
begin
return
(I => 42);end
Constructor;end
Limited_Private_Samples;
with
Limited_Private_Samples;use
Limited_Private_Samples;procedure
Tryis
U: Uninitialised; -- very bad P: Preinitialised; -- has initial value (good) D1: Dynamic_Initialisation; -- has initial value (good) D2: Dynamic_Initialisation := Constructor (0); -- Ada 2005 initialisation D3: Dynamic_Initialisationrenames
Constructor (0); -- already Ada 95 -- I: Needs_Constructor; -- Illegal without initialisation N: Needs_Constructor := Constructor (0); -- Ada 2005 initialisationbegin
null
;end
Try;
Note that D3 is a constant, whereas all others are variables.
Also note that the initial value that is defined for the component of Preinitialised is evaluated at the time of object creation, i.e. if an expression is used instead of the literal, the value can be run-time dependent.
X, Y: Preinitialised;
In this declaration of two objects, the initial expression will be evaluated twice and can deliver different values, because it is equivalent to the sequence:[1]
X: Preinitialised; Y: Preinitialised;
So X is initialised before Y.
See also
editAda 95 Reference Manual
editAda 2005 Reference Manual
editAda Quality and Style Guide
editReferences
edit- ↑
ISO/IEC 8652:2007. "3.3.1 Object Declarations (7)". Ada 2005 Reference Manual.
Any declaration [...] with more than one defining_identifier is equivalent to a series of declarations each containing one defining_identifier from the list, [...] in the same order as the list.
{{cite book}}
: Unknown parameter|chapterurl=
ignored (|chapter-url=
suggested) (help)