Struct Embedding in Ada

Based on the input data extracted, our target language is Ada. Below is the translation of the provided code example:

Go by Example: Struct Embedding

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Vectors; 

procedure Main is

   -- Define a type `Base` as a record with a single integer field `Num`
   type Base is record
      Num : Integer;
   end record;

   -- Define a method for type `Base` to describe itself
   function Describe(B : Base) return String is
   begin
      return "base with num=" & Integer'Image(B.Num);
   end Describe;

   -- Define a type `Container` that "embeds" `Base` and has an additional string field `Str`
   type Container is record
      B : Base;
      Str : String (1 .. 50);
   end record;

begin
   -- When creating structs with literals, we must initialize the embedding explicitly; here the embedded type serves as the field name.
   declare
      CO : Container := (B => (Num => 1), Str => "some name                              ");
   begin
      -- We can access the base’s fields directly on CO
      Put_Line("co={num: " & Integer'Image(CO.B.Num) & ", str: " & CO.Str & "}");

      -- Alternatively, we can spell out the full path using the embedded type name
      Put_Line("also num: " & Integer'Image(CO.B.Num));

      -- Since `Container` embeds `Base`, the methods of `Base` also become methods of a `Container`. 
      -- Here we invoke a method that was embedded from `Base` directly on `CO`.
      Put_Line("describe: " & Describe(CO.B));

      -- Define an interface type `Describer` to declare the `Describe` method signature
      type Describer is interface;
      procedure Describe(X : in out Describer) is abstract;

      -- Make `Container` implement the `Describer` interface by aliasing the Describe method
      type Container_Describer is new Container and Describer with null record;

      -- Embedding structs with methods may be used to bestow interface implementations onto other structs.
      -- Here, we see that a `Container` now implements the `Describer` interface because it embeds `Base`.
      procedure Describe(X : in out Container_Describer) is
      begin
         Put_Line("describer: " & Describe(X.B));
      end Describe;

      New_Container : Container_Describer := (Container'(B => (Num => 1), Str => "description"));

      -- Call the Describe method on the new container instance
      Describe(New_Container);
   end;

end Main;

To run this program, save the code in main.adb and use GNAT (the Ada compiler) to compile and run it.

$ gnatmake main.adb
$ ./main
co={num:  1, str: some name                              }
also num:  1
describe: base with num=  1
describer: base with num=  1

Let’s learn more about the language by exploring further examples.