❌ About FreshRSS

Normal view

There are new articles available, click to refresh the page.
Before yesterdayNewest questions tagged ada - Stack Overflow

Access-to-variable designates constant when trying to pass a pointer to vector element

This question is a follow-up to How to get access to a record field .

The more complex (now) code involves binding a whole vector of records. Something along the lines below:

type Tag is record
  Field : String := "value";
end record;

type Tag_Access is access all Tag;

package Tags_Vectors is new Indefinite_Vectors
  (Index_Type   => Positive,
   Element_Type => Wheel_Tag);

procedure Bind_Tag (T : in out Tag_Access; Stmt : Gnade.Statement) is
begin
    Gnade.Bind_Text (Stmt, T.Field'Address, T.Field'Length);
end Bind_Tag;

procedure Insert_Tags is
  Stmt : Gnade.Statement;
  Tags : Tags_Vectors.Vector;
  --  Make necessary arrangements to populate the Stmt and Tags
  C : Tags_Vectors.Cursor := Tags.First;
begin
  while Tags_Vectors.Has_Element (C) loop
         Bind_Tag (Stmt, Tags_Vectors.Element (C)'Access);
         Tags_Vectors.Next (C);
  end loop;
  Gnade.Step (Db, Stmt);
end Insert_Tag;

I'm not sure what kind of thing Tags_Vector.Element (C) returns. Syntactically, at least, it seems Ada doesn't object to this having an access attribute. But, I don't understand the error (which side does it think is the variable and which side is the constant?) Why is it bad that access to variable designates a constant? (Is it trying to say that I might be changing the value of a constant? -- but I never wanted any of those things to be constants...)

How to get access to a record field

Some general context for my problem first.

I need to bind some arguments of a prepared statement using GNATCOLL SQLite bindings. These bindings expect C character pointer as an input (beside other things). This requirements creates two problems on Ada's end:

Problem 1

The variable pointed to by the "bound" pointer must not perish until the prepared statement is finalized (otherwise it will store a pointer to garbage). But, for queries that operate on the same type of record it would be desirable to extract the part of binding of arguments (which are obtained from the record fields) into a separate procedure. If such procedure returns before the statement is finalized the variables (on the stack of such procedure) will be deleted, and pointers now point to garbage.

Problem 2

I only know of three instances in Ada of creating pointers: new-ing, taking a pointer to a function / procedure and taking a pointer to a variable. Since the bindings want a pointer, I don't know how to extract such a pointer from a record unless I "manually unpack" it into a bunch of local variables. Needless to say this is ugly, repetitive and very prone to copy-and-paste error. This also leads to the lifetime issues (since variables "unpacked" in such a way will be deleted before the actual value they are used to capture still exists.)

Example

type Tag is record
  Field : String := "value";
end record;

type Tag_Access is access all Tag;

procedure Bind_Tag (T : Tag_Access; Stmt : Gnade.Statement) is
  --  This variable will vanish before the statement is executed
  Field : aliased constant String := T.Field;
begin
    Gnade.Bind_Text (Stmt, Field'Address, Field'Length);
end Bind_Tag;

procedure Insert_Tag (T : Tag) is
  --  Necessary connection initialization and building of prepared statement
  Tc : Tag := T;  --  Creating a useless variable only to please the compiler
  Ta : Tag_Access := Tc'Access;
begin
  Bind_Tag (Ta, Stmt);
  --  Here, bindings are dead, so we are executing garbage
  Gnade.Step (Db, Stmt);
end Insert_Tag;

If I may enter a plea

I suspect this may be helped by using objects (i.e. new-ing something). I haven't researched this approach because my first experience with Ada (I'm still learning) was very negative when contracting objects. Deallocation combined with absence of convenient object lifetime management (eg. equivalent of C++ RAII) makes using objects a very daunting task. I would like to stay away from this functionality as much as possible.


Edit

I found a way out of this particular conundrum: turns out SQlite can be instructed to make copies when binding strings. This isn't ideal, but at least I can get the strings into the database.

This doesn't mean that the question is solved though. I'd still like to know a more general way of dealing with record fields. Something that in eg. C would be accomplished by taking a pointer to the struct and then adding the size of the fields preceding the field of interest and adding that the the pointer.

How do you use the Reference_Type in Ada Hashed_Maps?

I want to create a symbol table as a hash map and keep a list of pointers into the symbol table to keep track of symbol table entries that need to be updated. I probably can't use cursors as pointers since they might change when new items are added to the symbol table. I can't use access types as I don't know whether the Insert procedure stores the element passed to it or makes a copy and stores that. It looks like I'm supposed to use a Reference_Type. But the Reference_Type is causing me problems because it is unconstrained.

This doesn't work:

with Ada.Containers.Indefinite_Hashed_Maps;
with Ada.Containers.Vectors;
with Ada.Strings.Hash;

package Types is
type Memory_Address is mod 2**64;
type ID_Code        is (ID_VARIABLE, ID_LABEL); -- ...extend as necessary...

NULL_ADDRESS : constant Memory_Address := 0;

type Symbol_Table_Entry is record
    id      : ID_Code;
    address : Memory_Address;
end record;

package Symbol_Tables is new Ada.Containers.Indefinite_Hashed_Maps (
    Key_Type        => String,
    Element_Type    => Symbol_Table_Entry,
    Hash            => Ada.Strings.Hash,
    Equivalent_Keys => "="
);

subtype Symbol_Table is Symbol_Tables.Map;

subtype Symbol_Table_Pointer is Symbol_Tables.Reference_Type;

-- Quadruple: Red Dragon Book, p. 470

type Opcode is new Natural;

type Quadruple_List_Index is new Natural;

type Quadruple is record
    op     : Opcode;
    arg1   : Symbol_Table_Pointer;
    arg2   : Symbol_Table_Pointer;
    result : Symbol_Table_Pointer; -- lvalue or branch destination
end record;

package Quadruple_Lists is new Ada.Containers.Vectors (
    Index_Type   => Quadruple_List_Index,
    Element_Type => Quadruple
);

subtype Quadruple_List is Quadruple_Lists.Vector;

type Label_List is array(Natural range <>) of Quadruple_List_Index;

end Types;

I get "error: unconstrained subtype in component declaration" for the fields of Quadruple defined as Symbol_Table_Pointer. I have searched on the internet but have found no good examples of how to use Reference_Type. Could someone please explain how to make this work?

What is "extension aggregate" and why do I need it?

I'm trying to use GNAT's SQLite bindings. And I want some way to get errors from these bindings. Trying to read through the code, I found that I can set up the connection by providing a mystery object that is supposed to handle errors...

No matter how I try to shape and provide this object, the library either won't accept it, or I get runtime access check errors (another bizarre aspect of this program as the pointer should be always alive since it's never leaving the scope of the procedure that declared it... but maybe it works differently in Ada).

The error I'm getting looks like this:

type of aggregate has private ancestor "Error_Reporter"
must use extension aggregate

The original Error_Reporter is defined as follows:

type Error_Reporter is abstract tagged private;
...
private

   type Error_Reporter is abstract tagged null record;

Anyways, below is the outline of the problematic code:

The header file:

   -- type Error_Handler is new Gse.Error_Reporter with private;
   type Error_Handler is new Gse.Error_Reporter with record
      Message : Asu.Unbounded_String;
   end record;
   
   type Error_Handler_Access is access Error_Handler;

   procedure On_Error
     (Self       : in out Error_Handler;
      Connection : access Gse.Database_Connection_Record'Class;
      Message    : String);

-- more stuff ...
   
-- private
--    type Error_Handler is new Gse.Error_Reporter with record
--       Message : Asu.Unbounded_String;
--    end record;

the implementation:

...
      declare
         pragma Suppress (Accessibility_Check);
         -- Handler : constant Error_Handler_Access :=
         --   new Error_Handler'(Message => Asu.Null_Unbounded_String);
         Handler : constant access Error_Handler :=
           new Error_Handler'(Message => Asu.Null_Unbounded_String);
         -- Handler : aliased Error_Handler;
         Descr         : Gse.Database_Description    :=
           Gss.Setup (Db_File, Errors => Handler);
--         Gss.Setup (Db_File, Errors => Handler'Access);
...

Commented code shows various things I tried. (Also, pragma has no effect).

Ideally, I don't want to new anything, unless this is the requirement from GNAT's interface.

Even better: if I could entirely avoid using this object (it should be possible to salvage the actual Sqlite connection from this wrapper and get access to return code and the error message), but the code is not very easy to read and is trying to make the user do things that I don't want (ORM, multiple layers of bindings that only complicate things) all while hiding the essential useful functionality. I'd appreciate any guidance in this direction.


UPDATE: In the end, my problem was I couldn't figure out how to use Bind_XXX group of procedures from Gnade package. And this is what prompted me to use the Execute package, which ultimately led to the problem with error reporting. To solve this, I finally figured out how to use Bind_XXX (the one giving me the most problems was Bind_Text due to pointer translation between Ada and C). Once that worked, I rewrote the code to use just Gnade.

Creating custom Sax reader

There's something about polymorphism in Ada that I don't understand. (Or maybe it's the package naming?) I'm trying to parse an XML file using xmlada library and I followed the example I found in tests for this library that uses Debug_Reader. Below is the problematic code:

--  cog_cli-xml.adb
with Ada.Strings.Unbounded;
with Sax.Readers;
with Input_Sources.Strings;
with Unicode.CES.Basic_8bit;
with Cog_Cli.Xml_Reader;
with Cog_Cli_Doc;

package body Cog_Cli.Xml is
   
   package Asu renames Ada.Strings.Unbounded;
   package Ccxr renames Cog_Cli.Xml_Reader;
   package Sr renames Sax.Readers;
   package Iss renames Input_Sources.Strings;
   package Ccd renames Cog_Cli_Doc;
   package U8bit renames Unicode.CES.Basic_8bit;

   function Cli_Help (Command : String) return String is
      Doc_Reader : Ccxr.Reader;
      Input      : Iss.String_Input;
      Cli_Help   : constant Ccd.Content_Type := Ccd.Get_Content ("cli.xml");
   begin
      Iss.Open (Cli_Help.Content.all,
                Encoding => U8bit.Basic_8bit_Encoding,
                Input => Input);
      Ccxr.Set_Command (Doc_Reader, Command);

      Sr.Set_Feature (Doc_Reader, Sr.Namespace_Prefixes_Feature, False);
      Sr.Set_Feature (Doc_Reader, Sr.Namespace_Feature, False);
      Sr.Set_Feature (Doc_Reader, Sr.Validation_Feature, False);

      Sr.Parse (Doc_Reader, Input);

      Iss.Close (Input);

      return Asu.To_String (Doc_Reader.Help);
   end Cli_Help;

end Cog_Cli.Xml;
--  cog_cli-xml_reader.ads
with Sax.Readers;
with Unicode.CES;
with Sax.Attributes;
with Ada.Strings.Unbounded;

package Cog_Cli.Xml_Reader is
   
   package Asu renames Ada.Strings.Unbounded;

   type Reader is new Sax.Readers.Reader with private;

   procedure Start_Element
     (Handler       : in out Reader;
      Namespace_URI : Unicode.CES.Byte_Sequence := "";
      Local_Name    : Unicode.CES.Byte_Sequence := "";
      Qname         : Unicode.CES.Byte_Sequence := "";
      Atts          : Sax.Attributes.Attributes'Class);

   procedure End_Element
     (Handler       : in out Reader;
      Namespace_URI : Unicode.CES.Byte_Sequence := "";
      Local_Name    : Unicode.CES.Byte_Sequence := "";
      Qname         : Unicode.CES.Byte_Sequence := "");

   procedure Characters
     (Handler : in out Reader;
      Ch      : Unicode.CES.Byte_Sequence);

   procedure Set_Command (Handler : in out Reader; Command : String);

   procedure Set_Help (Handler : in out Reader; Help : String);
   
private
   type Reader is new Sax.Readers.Reader with record
      Command : Asu.Unbounded_String;
      Help    : Asu.Unbounded_String;
   end record;

end Cog_Cli.Xml_Reader;
with Ada.Text_IO;
with Ada.Strings.Unbounded;

package body Cog_Cli.Xml_Reader is
   
   package Ati renames Ada.Text_IO;
   package Asu renames with Ada.Strings.Unbounded;

   procedure Start_Element
     (Handler       : in out Reader;
      Namespace_URI : Unicode.CES.Byte_Sequence := "";
      Local_Name    : Unicode.CES.Byte_Sequence := "";
      Qname         : Unicode.CES.Byte_Sequence := "";
      Atts          : Sax.Attributes.Attributes'Class) is
   begin
      null;
   end Start_Element;
   
   procedure Characters
     (Handler : in out Reader;
      Ch      : Unicode.CES.Byte_Sequence) is
   begin
      null;
   end Characters;
   
   procedure End_Element
     (Handler       : in out Reader;
      Namespace_URI : Unicode.CES.Byte_Sequence := "";
      Local_Name    : Unicode.CES.Byte_Sequence := "";
      Qname         : Unicode.CES.Byte_Sequence := "") is
   begin
      null;
   end End_Element;

   procedure Set_Command (Handler : in out Reader; Command : String) is
   begin
      Handler.Command := Asu.To_Unbounded_String (Command);
   end Set_Command;

   procedure Set_Help (Handler : in out Reader; Help : String) is
   begin
      Handler.Help := Asu.To_Unbounded_String (Help);
   end Set_Help;

end Cog_Cli.Xml_Reader;

The problem is that Sr.Set_Feature doesn't believe that Doc_Reader is the right type... I have no idea why. The literal error I'm getting is:

cog_cli-xml.adb:27:09: error: no candidate interpretations match the actuals:
cog_cli-xml.adb:27:23: error: expected private type "Readers.Reader" defined at sax-readers.ads:778
cog_cli-xml.adb:27:23: error: found private type "Xml_Reader.Reader" defined at cog_cli-xml_reader.ads:10

Square root of Big_Real in Ada

I am trying to calculate the square root of big numbers (around 16 digits) using the Big_Reals package. I have the following square root function which uses the Newton-Raphson method

pragma Ada_2022;
with Ada.Numerics.Big_Numbers.Big_Reals;
use Ada.Numerics.Big_Numbers.Big_Reals;

function Big_Sqrt(X: Big_Real) return Big_Real is
    package Converter is new Float_Conversions(Float);
    use Converter;
    Z: Big_Real := X;
    Big_Half: Big_Real := To_Big_Real(0.5);
begin
    for I in 1..32 loop
        Z := Big_Half * (Z+X/Z);
        Put_Line(Z'Image);
    end loop;
    return Z;
end Big_Sqrt;

The output with input 1813789079679324 is

906894539839662.500
453447269919832.249
226723634959918.124
113361817479963.062
56680908739989.531
28340454370010.765
14170227185037.382

raised STORAGE_ERROR : Ada.Numerics.Big_Numbers.Big_Integers.Bignums.Normalize: big integer limit exceeded

I'm assuming this happens because although the whole part of the number is getting smaller there is too much space being used for the decimal part but I can't find a way to reduce the precision of the decimal part.

Overloaded Subprograms in Ada

Our Programming Languages professor told us that:

"In Ada, the return type of an overloaded function can be used to disambiguate calls (thus two overloaded functions can have the same parameters)"

So this implies that in Ada, we could do something like this:

function Func (Var : Integer) return Integer;
function Func (Var : Integer) return Float;

And then create different implementations of these two functions, therefore overloading them.

This does not make much sense to me, how can the return type alone be sufficient to distinguish between overloaded subprograms? How would we even go about deciding which one of these functions we meant to call when we do decide to use them?

Problem with subtype usage in concurrent Ada program

I am working on a concurrent programming problem in Ada. The task is to simulate a bridge over which different cars can pass from different directions. The complication lies in the fact that, if an ambulance is present, the cars must give it absolute priority.

Here is the code I have developed:

with Ada.Text_IO; use Ada.Text_IO;

procedure Main is
   type Direccion is (Norte, Sur);

   task type Vehiculo (ID : Integer; Acceso : Direccion);
   task type Ambulancia;

   protected type Puente is
      entry Entrar (ID : Integer; Acceso : Direccion);
      entry Salir (ID : Integer);
   private
      Puente_Ocupado : Boolean := False;
      Ambulancia_Esperando : Boolean := False;
      Ambulancia_En_Puente : Boolean := False;
      Coches_En_Espera : Integer := 0;
      Ambulancia_En_Espera : Boolean := False;

      procedure Entrar_Ambulancia;
      procedure Entrar_Coche(ID : Integer; Acceso : Direccion);
   end Puente;

   task body Vehiculo is
   begin
      Put_Line ("El coche" & Integer'Image(ID) & " estΓ‘ en ruta en direcciΓ³n " & Direccion'Image(Acceso) & "!");

      Puente.Entrar(ID, Acceso);
      delay(1.0); -- Simula el tiempo que tarda en cruzar el puente
      Puente.Salir(ID);
   end Vehiculo;

   task body Ambulancia is
   begin
      Put_Line ("La ambulancia 112 estΓ‘ en ruta");
      Puente.Entrar(112, Norte); -- Cambiado a un acceso especΓ­fico, puedes ajustar segΓΊn tus necesidades
      delay(0.5); -- Simula el tiempo que tarda en cruzar el puente
      Puente.Salir(112);
   end Ambulancia;

   protected body Puente is
      entry Entrar (ID : Integer; Acceso : Direccion) when not Puente_Ocupado is
      begin
         if ID = 112 then
            Entrar_Ambulancia;
         else
            Entrar_Coche(ID, Acceso);
         end if;
      end Entrar;

      entry Salir (ID : Integer) when Puente_Ocupado is
      begin
         if ID = 112 then
            Ambulancia_En_Puente := False;
         else
            Puente_Ocupado := False;
            Coches_En_Espera := 0;
         end if;
      end Salir;

      procedure Entrar_Ambulancia is
      begin
         if Puente_Ocupado then
            Ambulancia_Esperando := True;
            Ambulancia_En_Espera := True;
            Put_Line ("+++++Ambulancia 112 espera para entrar");
         else
            Puente_Ocupado := True;
            Ambulancia_En_Puente := True;
            Put_Line ("+++++Ambulancia 112 estΓ‘ en el puente");
         end if;
      end Entrar_Ambulancia;

      procedure Entrar_Coche(ID : Integer; Acceso : Direccion) is
      begin
         if Puente_Ocupado or Ambulancia_En_Puente then
            Coches_En_Espera := Coches_En_Espera + 1;
            Put_Line ("El coche" & Integer'Image(ID) & " espera a la entrada " & Direccion'Image(Acceso) & ". Esperan " & Integer'Image(Coches_En_Espera) & " coches.");
         else
            Puente_Ocupado := True;
            Put_Line ("El coche" & Integer'Image(ID) & " entra en el puente. Esperan en la " & Direccion'Image(Acceso) & ": " & Integer'Image(Coches_En_Espera) & " coches.");
         end if;
      end Entrar_Coche;
   end Puente;
   
   -- CreaciΓ³n de instancias
   Coche1 : Vehiculo(1, Norte);
   Coche2 : Vehiculo(2, Sur);
   Coche3 : Vehiculo(3, Norte);
   Coche4 : Vehiculo(4, Sur);
   Coche5 : Vehiculo(5, Norte);
   Amb : Ambulancia;
   
begin   
   -- Esperar la finalizaciΓ³n de los procesos
   while not (Coche1'Terminated and Coche2'Terminated and Coche3'Terminated and Coche4'Terminated and Coche5'Terminated and Amb'Terminated) loop
      null;
   end loop;

   -- Mensajes finales
      Put_Line("Todos los vehΓ­culos han cruzado el puente y la ambulancia ha completado su ruta.");
end Main;

The current code generates errors indicating "invalid use of subtype mark in expression or call". I am using subtypes to represent directions (North, South), "(Norte, Sur)", and there seems to be a problem when trying to use them in certain expressions or calls.

I would appreciate any guidance on how to fix this problem and any suggestions on how to improve the efficiency or clarity of the code.

Compiler Error:

main.adb:27:7: error: invalid use of subtype mark in expression or call
main.adb:29:7: error: invalid use of subtype mark in expression or call
main.adb:35:7: error: invalid use of subtype mark in expression or call
main.adb:37:7: error: invalid use of subtype mark in expression or call

  • I have tried to review the Ada documentation, but I have not been able to identify the specific problem in my code.
  • I am using subtypes to represent addresses, and I suspect the error might be related to their use in procedure calls within tasks. Thanks in advance for any help provided.

Generating Ada bindings for C headers (Gem #59) doesn't work any more

When I used this method a few years ago, with Ada from the Ubuntu repository, it worked fine. Now, with my installation from Adacore, not so anymore.

The method consists of 2 commands (time.h as example)

  1. g++ -c -fdump-ada-spec -C /usr/include/time.h
  2. gcc -c -gnat05 *.ads

While the first command executes without any problem, the second one returns:

gcc: fatal error: cannot execute β€˜gnat1’: execvp: No such file or directory

It doesn't depend on the -gnat05 option. There is indeed no gnat1 in the bin directory of the Ada installation. Mine is version 2021. I am reluctant to install the GNU version in parallel, I might mix up things.

Any other idea?

Type not visible in child package

I have the following parent package which defines several types

aes.ads

package AES is    
    type Byte is range 0..2**8  - 1;
    type Input_Buffer is array(Natural range <>) of Byte;
    type Output_Buffer is array(Natural range <>) of Byte;
    type Key is array(Natural range <>) of Byte;
    subtype AES_128_Key is Key(0..127);
    subtype AES_192_Key is Key(0..191);
    subtype AES_256_Key is Key(0..255);
    type Operation is (Encrypt, Decrypt);

    function AES_CBC_128(Input: Input_Buffer; Key: AES_128_Key; Op: Operation) return Output_Buffer;
    function AES_CBC_192(Input: Input_Buffer; Key: AES_192_Key; Op: Operation) return Output_Buffer;
    function AES_CBC_256(Input: Input_Buffer; Key: AES_256_Key; Op: Operation) return Output_Buffer;

private
    type Word is range 0..2**32 - 1;
    type State is array(0..3, 0..3) of Byte;
    type States is array(Natural range <>) of State;
    type Round_Key is array(0..16) of Byte;
    type Key_Schedule is array(Natural range <>) of Round_Key;
end AES;

aes.adb

with AES.AES_Cipher; use AES.AES_Cipher;
with AES.AES_Inv_Cipher; use AES.AES_Inv_Cipher;

package body AES is

-- other definitions

function AES_Common(St: State; K: Key; Op: Operation) return State is
    Schedule: Key_Schedule := Key_Expansion(K);
begin
    return (case Op is
        when Encrypt => Cipher(St, Schedule),
        when Decrypt => Inv_Cipher(St, Schedule)
    );
end AES_Common;

-- more definitions

end AES;

and then two child packages (aes-aes_inv_cipher is very similar to aes-aes_cipher so has been omitted)

aes-aes_cipher.ads

package AES.AES_Cipher is
    function Cipher(St: State; Schedule: Key_Schedule) return State;
end AES.AES_Cipher;

aes-aes_cipher.adb

package body AES.AES_Cipher is

function Cipher(St: State; Schedule: Key_Schedule) return State is
begin
    
    return St;
end Cipher;

end AES.AES_Cipher;

These are called from main.adb

with AES; use AES;

procedure Main is
    Input: Input_Buffer(0..35) := (others => Byte(44));
    K: AES_128_Key := (others => Byte(55));
    Output: Output_Buffer(0..35);
begin
    Output := AES_CBC_128(Input, K, Encrypt);
end Main;

This does not compile with the following error

aes-aes_cipher.ads:2:25: error: "State" is not visible (more references follow)
aes-aes_cipher.ads:2:25: error: non-visible (private) declaration at aes.ads:17
aes-aes_cipher.ads:2:42: error: "Key_Schedule" is not visible (more references follow)
aes-aes_cipher.ads:2:42: error: non-visible (private) declaration at aes.ads:20

I thought because aes-aes_cipher is a child package of aes it could access the private definitions in aes.ads but the error suggests otherwise. If this is not possible, how can I restructure the program so it works as expected? Removing private fixes it but those types should be private outside the package. I am using gnatmake version 13.2.0 on Windows.

How to Overload the Subscript/Subprogram Call Operator in Ada

We all know and love Ada.Containers.Vectors. Here's an example of its usage:

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

procedure Example is
   use Ada.Text_IO;

   package Vectors_Integer is new Ada.Containers.Vectors (Natural, Integer);
   use Vectors_Integer;

   My_Vec : Vector := 1 & 2 & 3;
begin
   Put_Line (Integer'Image (My_Vec (0)));
end Example;

My question is simple: how does My_Vec (0) work, and how can I recreate this behavior in a type of my own?

I have been searching the internet for a while but I can't find to seem any explanation for how this expression works. The subscript operator, which uses the same syntax as the function call operator, cannot be overloaded using the normal syntax for operator overloading. I've read the package specification for Ada.Containers.Vectors, and there doesn't seem to be any explicit means through which Vector overloads this operator. I had guessed that the Element function might have something to do with it, but have been unable to use it to define a type of my own that replicates Vector's behavior. I'm at a complete loss on how to overload the subscript operator, even though it is clear that it is possible.

Ada design by contracts critical software

I have a question related to applying contracts in a critical environment.

Imagine I have the following function to divide:

function div (dividend, divisor : Float) return Float
with Pre => divisor /= 0;

Well, for me the pre-condition is part of the signature of the function and every client must be aware of the contract, if a client pass a zero to the divisor argument is its fault bacause he is violating the contract and thus the function will fail. In testing, with pre-conditions activated, the code will fail showing a contract violation and, in production with pre-conditions deactivated, would fail raising a constraint.

As a constraint error is not acceptable in a critical environment, this is what the client is requiring me for the implementation, to call a module that manages inconsistencies:

function div (dividend, divisor : Float) return Float is
begin
  if divisor = 0 then
    InconsistencyManager.inconsistency ("Some Log"); --It firstly logs a message and then does an infinite loop
  end;

  return dividend / divisor; --If everything is ok, return the division
end div;

For me this side effect for a function its quite weird, and for me violating a contract is like passing the wrong type to a subprogram, the difference is that this kind of error is caught at compilation time and the contract violation, if there aren't enough tests, could stop the execution of the program when is already installed.

Do you really has to protect against human stupidity like this? Do you really has to penalize the function execution making always that question?

How to initialize a record with a list element in ada

By: bal
10 November 2023 at 22:53

When trying to instantiate a list element in a record my program does not work. I get the following error in the declaration of the subtype list_unbounded: hear.adb:25:65: error: prefix must not be a generic package hear.adb:25:65: error: use package instantiation as prefix instead hear.adb:25:70: error: incorrect constraint for this kind of type gnatmake: "hear.adb" compilation error

Procedure hear is:
    ind : Integer;
    Subtype List_Unbounded is Ada.Containers.Doubly_Linked_Lists.List(ELement_Type => Ada.Strings.UNbounded.Unbounded_String);
    Type T_Node is record
        Name : Ada.Strings.Unbounded.UNbounded_String;
        N_List : List_Unbounded;
    end record;
begin
(...)

Trying to compile a simple Ada program, getting GNAT compiling error in OS 14.1 (23B73) on a M2 MBP

❯ alr build
β“˜ Building myproj/myproj.gpr...
Link
   [link]         myproj.adb
0  0x10034af43  __assert_rtn + 64
1  0x10024cf43  ld::AtomPlacement::findAtom(unsigned char, unsigned long long, ld::AtomPlacement::AtomLoc const*&, long long&) const + 1411
2  0x100269431  ld::InputFiles::SliceParser::parseObjectFile(mach_o::Header const*) const + 19745
3  0x100279e44  ld::InputFiles::parseAllFiles(void (ld::AtomFile const*) block_pointer)::$_7::operator()(unsigned long, ld::FileInfo const&) const + 1380
4  0x7ff8051315cd  _dispatch_client_callout2 + 8
5  0x7ff805141e3e  _dispatch_apply_invoke + 214
6  0x7ff80513159a  _dispatch_client_callout + 8
7  0x7ff80514099d  _dispatch_root_queue_drain + 879
8  0x7ff805140f22  _dispatch_worker_thread2 + 152
9  0x7ff8052d5c06  _pthread_wqthread + 262
ld: Assertion failed: (resultIndex < sectData.atoms.size()), function findAtom, file Relocations.cpp, line 1336.
collect2: error: ld returned 1 exit status
gprbuild: link of myproj.adb failed
gprbuild: failed command was: /users/sdey02/.config/alire/cache/dependencies/gnat_native_13.2.1_c21501ad/bin/gcc myproj.o b__myproj.o -L/Users/sdey02/myproj/obj/development/ -L/Users/sdey02/myproj/obj/development/ -L/users/sdey02/.config/alire/cache/dependencies/gnat_native_13.2.1_c21501ad/lib/gcc/x86_64-apple-darwin21.6.0/13.2.0/adalib/ /users/sdey02/.config/alire/cache/dependencies/gnat_native_13.2.1_c21501ad/lib/gcc/x86_64-apple-darwin21.6.0/13.2.0/adalib/libgnat.a -Wl,-rpath,@executable_path/..//obj/development -Wl,-rpath,@executable_path/../..//.config/alire/cache/dependencies/gnat_native_13.2.1_c21501ad/lib/gcc/x86_64-apple-darwin21.6.0/13.2.0/adalib -o /Users/sdey02/myproj/bin//myproj
error: Command ["gprbuild", "-s", "-j0", "-p", "-P", "/Users/sdey02/myproj/myproj.gpr"] exited with code 4
error: Compilation failed.

Error seems to be this: ld: Assertion failed: (resultIndex < sectData.atoms.size()), function findAtom, file Relocations.cpp, line 1336.

I ran the alr build command and expected the crate to build but instead got an exited with code 4 error.

I checked other threads and it seems to be an issue with the latest version of cmd line tools. What are my options to fix this?

I am trying to implement this using a circular queue. My program executes but says terminated succesfully when build&ran

LinkSort.adb file

with Ada.Text_IO; use Ada.Text_IO;

procedure LinkSort is

  type JobType is (Accountant, Analysist, Manager, Manufacturing, Programmer, Inventory, Sales, SoftwareEnginner);
  package JobTypeIO is new Ada.Text_IO.Enumeration_IO(JobType); use JobTypeIO;

  type EmpName is (Ben, Betty, Bob, Damon, Darlene, David, Desire, Donald, Dustin, Jerry, Kevin, Mary, Marty, Sable, Sam, Sara, Teddy, Tom);
  package EmpNameIO is new Ada.Text_IO.Enumeration_IO(EmpName); use EmpNameIO;

  type LegalResponce is (yup, y, yes, affirmative, nope, no, n, negative);
  subtype PositiveResponce is LegalResponce range yup..affirmative;
  package LegalIO is new Ada.Text_IO.Enumeration_IO(LegalResponce); use LegalIO;

  package IntIO is new Ada.Text_IO.Integer_IO(Integer); use IntIO;

  type Emp is record
    Name: EmpName;
    Job: JobType;
    age: integer;
  end record;

  SortByJob: Array(JobType) of integer := (others =\> 0);

  SortSpace: Array(1..200) of Emp;
  Avail: integer := 1; -- Dynamic storage allocator.
  Pt: integer;

  Again: LegalResponce := affirmative;

begin

  while (Again in PositiveResponce) loop
    put("Enter name: "); get(SortSpace(Avail).Name); --Get emp info.
    put("Enter Job type: "); get(SortSpace(Avail).Job);
    
    -- Insert in appropriate list (by job).
    SortSpace(Avail).Next := SortByJob(SortSpace(Avail).Job);
    SortByJob(SortSpace(Avail).Job) := Avail;
    
    -- Prepare for next dynamically allocated node.
    Avail := Avail + 1; --Using static array allocation as opposed dynamic linked list.
    
    put("Enter another name (yup or nope): "); get(Again);
  end loop;

  -- Sort by job type.

  for I in JobType loop
    new_line; put("Job Type = "); put (I); new_line;
    
    Pt := SortByJob(I); -- Point to first node in job list.
    
    while Pt /= 0 loop
      put(SortSpace(Pt).Name); put(" "); put(SortSpace(Pt).Job);
      put(" link = "); put(SortSpace(Pt).Next,4); new_line;
    
      Pt := SortSpace(Pt).Next; -- Move down list.
    end loop;
  end loop;

end LinkSort;

main.adb file

procedure Main is
begin
  null;
end Main;

Stuck on what I should do next? I've tried to implement everything in the Ada.Text_IO in the main.adb file but errors occurred. I know i need to move something into the main file in order for the program to execute after it has been built. The output statement should be name, job type then sort space number.

Error: declarations must come before begins (Ada) [closed]

procedure Main is



begin



--  Insert code here.procedure LinkSort ;




  type JobType is (Accountant, Analysist, Manager, Manufacturing, Programmer,
             Inventory, Sales, SoftwareEnginner);
package JobTypeIO is new Ada.Text_IO.Enumeration_IO(JobType); use JobTypeIO;



type EmpName is (Ben, Betty, Bob, Damon, Darlene, David, Desire, Donald, Dustin,Jerry, Kevin, Mary, Marty, Sable, Sam, Sara, Teddy, Tom);package EmpNameIO is new Ada.Text_IO.Enumeration_IO(EmpName); use EmpNameIO;




type LegalResponce is (yup, y, yes, affirmative, nope, no, n, negative);subtype PositiveResponce is LegalResponce range yup..affirmative;package LegalIO is new Ada.Text_IO.Enumeration_IO(LegalResponce); use LegalIO;



package IntIO is new Ada.Text_IO.Integer_IO(Integer); use IntIO;null;end Main;



I've tried to insert declarations before begin but more errors pop up. This is supposed to use IO-redirection but I cannot figure out what I am missing.

Can I instantiate a generic within the same unit in Ada?

It doesn't seem like this is possible, but I haven't seen a definitive answer. What I want to do is define a generic subprogram with some generic formal parameters and instantiate it in the same package, like the following simplified and untested example:

generic
    Proc_Address : access System.Address;
    type Param_1_Type (<>) is private;
procedure Procedure_IP(Param_1 : Param_1_Type);

Instance_1_Address : System.Address := ...
procedure Instance_1 is new Procedure_IP(Instance_1_Address, type_1);
Instance_2_Address : System.Address := ...
procedure Instance_2 is new Procedure_IP(Instance_2_Address, type_2);
--etc

But this kind of thing keeps resulting in those "access before elaboration" errors. I can't seem to find any pragmas that will affect elaboration of a single subprogram; seems it has to be the whole package. Attempts to move the generic subprogram into a separate package have proven more troublesome than I had hoped because the specific stuff I want the function to do is closely related to other things happening in the same package.

Is there any way to resolve the elaboration order issue, so that I can keep the declaration and instantiations in the same package?

Option B is to rework this in a different way, like maybe passing a function pointer to a non-generic function or something, but doing it as a generic seems to be the cleanest way to go about it, especially since I'll need to refer to each of the intended instances a lot.

Does Ada have a type equivalent to Pascal's set?

I'm learning Ada as a spare-time activity and, while I realise that it is greatly inspired by Pascal, I can't find a type that is similar to Pascal's set.

set is built into the Pascal language itself and uses one bit per element. So, for example, var a: set of char; declares a (typically) 256-bit data type that can hold any set of characters.

In Ada, I can see that it has sets as part of its library (not a built-in language feature) but those are more like Java's HashSet or C++'s unordered_set and take up much more memory than 1 bit per element. Am I missing something?

macOS Sonoma GtkAda installed, but Gnat Studio and others do not see it

I have Macs with macOS Sonoma and I have successfully compiled and installed GtkAda from source that I got from AdaCore, with no errors. It's installed at /usr/local/lib/gnat and /usr/local/lib/gtkada, but nothing sees it. I use Gnat Studio and of course it complains about not finding "gtkada" compiling from the command line has the same issue. I have not updated the LD_LIBRARY_PATH, and related because I don't know how if that's the issue. This works on Linux and Windows very easily, but I'm not sure what else to do at this point. I have listed my Macs with Sonoma, but I've actually never had it work with Ventura either, so I don't think that has anything to do with it. I know I'm missing something, and probably something simple.

❌
❌