Defer in Ada

Ada doesn’t have a direct equivalent to Go’s defer keyword. However, we can achieve similar functionality using Ada’s exception handling mechanism and the finalization concept. Here’s how we can implement a similar behavior:

with Ada.Text_IO;
with Ada.Exceptions;
with Ada.IO_Exceptions;

procedure Defer_Example is
   type File_Type is limited private;

   procedure Create_File (F : in out File_Type; Name : String);
   procedure Close_File (F : in out File_Type);
   procedure Write_File (F : in out File_Type);

   procedure Create_File (F : in out File_Type; Name : String) is
   begin
      Ada.Text_IO.Put_Line ("creating");
      Ada.Text_IO.Create (F, Ada.Text_IO.Out_File, Name);
   exception
      when others =>
         raise Ada.IO_Exceptions.Name_Error with "Could not create file";
   end Create_File;

   procedure Write_File (F : in out File_Type) is
   begin
      Ada.Text_IO.Put_Line ("writing");
      Ada.Text_IO.Put_Line (F, "data");
   end Write_File;

   procedure Close_File (F : in out File_Type) is
   begin
      Ada.Text_IO.Put_Line ("closing");
      Ada.Text_IO.Close (F);
   exception
      when others =>
         Ada.Text_IO.Put_Line (Ada.Text_IO.Standard_Error, "Error closing file");
         Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
   end Close_File;

   F : File_Type;
begin
   Create_File (F, "/tmp/defer.txt");

   begin
      Write_File (F);
   exception
      when others =>
         Close_File (F);
         raise;
   end;

   Close_File (F);
exception
   when E : others =>
      Ada.Text_IO.Put_Line (Ada.Text_IO.Standard_Error, 
                            "Unexpected error: " & Ada.Exceptions.Exception_Message (E));
      Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
end Defer_Example;

In this Ada example, we’ve implemented functionality similar to Go’s defer using Ada’s exception handling mechanism. Here’s how it works:

  1. We define a File_Type and procedures to create, write to, and close a file.

  2. In the main procedure, we create the file and then use a nested block to write to it.

  3. If an exception occurs during file writing, we ensure the file is closed in the exception handler before re-raising the exception.

  4. If no exception occurs, we close the file after writing.

  5. We’ve wrapped the entire main procedure in an exception handler to catch any unexpected errors.

This approach ensures that the file is always closed, whether an exception occurs or not, similar to how Go’s defer works.

To run the program:

$ gnatmake defer_example.adb
$ ./defer_example
creating
writing
closing

This Ada implementation provides similar functionality to the Go example, ensuring proper resource cleanup even in the face of exceptions.