Bounded & Unbounded Strings

Handle variable-length text with Ada.Strings.Unbounded (To_Unbounded_String, Append, &, Length, Element, Index, Replace_Slice, To_String), Ada.Strings.Unbounded.Text_IO, and Ada.Strings.Bounded (Generic_Bounded_Length, Max_Length, truncation policies, Length_Error), and choose between fixed, bounded and unbounded strings.

When text length varies at run time — user input, building messages, records holding names — fixed String objects become awkward. Ada provides two standard variable-length string types: Unbounded_String, which grows on the heap with automatic memory management, and Bounded_String, which varies up to a fixed maximum without any heap allocation (preferred in embedded and high-integrity systems).

Unbounded_String

Ada.Strings.Unbounded defines Unbounded_String, a controlled type whose storage is allocated and freed automatically. Convert with To_Unbounded_String and To_String; Null_Unbounded_String is the empty value (and the default). Operations mirror Ada.Strings.Fixed: Append, & (mixing String and Unbounded_String), Length, Element (S, I), Replace_Element, Slice, Index, Count, Replace_Slice, Insert, Delete, Head, Tail, Trim, and comparisons with String operands. Ada.Strings.Unbounded.Text_IO provides Put_Line and Get_Line directly on unbounded strings. Unbounded strings are ideal in records and containers, since each component can hold text of any length.

• To_Unbounded_String / To_String convert. • Append, &, Length, Element, Index, Replace_Slice, Slice ... • Memory is managed automatically (controlled type). • Ada.Strings.Unbounded.Text_IO for direct I/O.

Bounded_String

Ada.Strings.Bounded.Generic_Bounded_Length is a generic package you instantiate with a maximum: 'package Name_Str is new Ada.Strings.Bounded.Generic_Bounded_Length (Max => 12);'. Its Bounded_String holds 0 .. Max characters inline (no heap), so it is safe for systems that forbid dynamic allocation. Operations take an optional Drop parameter controlling what happens on overflow: Ada.Strings.Error (default) raises Length_Error, Right truncates the end, Left truncates the start. Different instantiations are different types, which prevents mixing, e.g., names and addresses by accident.

• Instantiate Generic_Bounded_Length (Max => N). • No heap; storage is fixed at Max. • Drop => Error (Length_Error) | Left | Right.

Choosing a String Type

Use fixed String for constants, parameters and computed expressions (the most common and most efficient choice — subprograms should usually take String parameters). Use Unbounded_String when lengths vary widely and heap use is acceptable (applications, tools). Use Bounded_String when there is a known upper limit or heap allocation is forbidden (embedded, SPARK, certified code).

Pick the simplest type that fits the lifetime and length of the text.

Type               Length              Storage     Typical use
String             fixed per object    stack       constants, parameters, results
Bounded_String     0 .. Max            inline      embedded, known limits
Unbounded_String   any                 heap (auto) records, containers, general text

Code Examples

The unbounded string grows freely; joining a list of words is simple with Append. The bounded string reaches exactly 12 characters ("Grace Hopper"), so a further Append raises Length_Error by default, while Drop => Right silently keeps the first 12 characters. Output: Text = Ada Lovelace (1815) Length = 19 Element (Text, 1) = A Index of "Love" = 5 After Replace_Slice: Augusta Ada Lovelace (1815) safe, readable, reliable Words = "safe, readable, reliable"? TRUE Bounded: Grace Hopper (length 12, max 12) Appending past Max_Length raised Length_Error With Drop => Right: [Grace Hopper] S: Unbounded_String:= "text";

S : Unbounded_String := To_Unbounded_String ("text");

A String literal is not an Unbounded_String; convert explicitly (or use & with an existing unbounded value).

procedure Log (Msg: Unbounded_String); -- API for all callers procedure Log (Msg: String);

Prefer String parameters; callers convert only when they hold unbounded values.

Append (Short, Long_Text); -- assuming truncation Append (Short, Long_Text, Drop => Ada.Strings.Right);

Bounded operations raise Length_Error by default; request truncation explicitly.

Which string type never uses the heap and has a maximum length? A. String B. Bounded_String C. Unbounded_String D. Wide_String

What does a bounded Append raise by default when exceeding Max? A. Constraint_Error B. Storage_Error C. Ada.Strings.Length_Error D. Nothing, it truncates

C. Length_Error (verified in the example).

How do you convert an Unbounded_String U to String? A. String (U) B. To_String (U) C. U'Image D. U.all B. To_String (U).

Which is the best parameter type for a general 'print message' procedure? A. String B. Unbounded_String C. Bounded_String D. access String

A. String — callers of any string kind can supply one.

Trace the bounded/unbounded example.

Real output: Text = Ada Lovelace (1815) Length = 19 Element (Text, 1) = A Index of "Love" = 5 After Replace_Slice: Augusta Ada Lovelace (1815) safe, readable, reliable Words = "safe, readable, reliable"? TRUE Bounded: Grace Hopper (length 12, max 12) Appending past Max_Length raised Length_Error With Drop => Right: [Grace Hopper]

with Ada.Text_IO;               use Ada.Text_IO;
with Ada.Strings.Unbounded;     use Ada.Strings.Unbounded;
with Ada.Strings.Bounded;
with Ada.Strings.Unbounded.Text_IO;

procedure L22_Unbounded is
   --  Bounded strings: a generic instantiated with a maximum length
   package Name_Str is new Ada.Strings.Bounded.Generic_Bounded_Length (Max => 12);
   use Name_Str;

   Text  : Unbounded_String := To_Unbounded_String ("Ada");
   Words : Unbounded_String;                        --  initially empty
   Short : Bounded_String := To_Bounded_String ("Grace");
   type Word_List is array (Positive range <>) of Unbounded_String;
   List  : constant Word_List := [To_Unbounded_String ("safe"),
                                  To_Unbounded_String ("readable"),
                                  To_Unbounded_String ("reliable")];
begin
   --  Unbounded strings grow and shrink as needed (heap managed automatically)
   Append (Text, " Lovelace");
   Text := Text & " (1815)";
   Put_Line ("Text   = " & To_String (Text));
   Put_Line ("Length =" & Natural'Image (Length (Text)));
   Put_Line ("Element (Text, 1) = " & Element (Text, 1));
   Put_Line ("Index of ""Love"" =" & Natural'Image (Index (Text, 
…