Search code examples
genericsadagnat

Trouble with generic linked list


I'm learning generics in Ada, so I implemented a simple linked list. Here is my code :

Linked_List.adb :
    package body Linked_List is
   function Get_First_Element return Element_Type is
   begin
       return Beginning.Value;
   end Get_First_Element;

   function Get_Last_Element return Element_Type is
      temp : Node := Beginning.all;
   begin
      while temp.Next /= null loop
         temp := temp.Next.all;
      end loop;
      return temp.Value;
   end Get_Last_Element;

   procedure Add_Element(data : Element_Type) is
      newNode : access Node;
   begin
      newNode := new Node;
      newNode.all.Value := data;
      if Beginning.all.Next = null then
         Beginning := newNode;
      else
         Last.Next := newNode;
         Last := newNode;
      end if;

   end Add_Element; 

   procedure Remove_Element(data : Element_Type) is 
      temp : access Node := Beginning;
      prev : Node;
   begin
      while temp /= null or temp.all.Value /= data loop
         prev := temp.all;
         temp := temp.Next;
      end loop;
      if temp = null then
         return;
      else
         prev.Next := temp.all.Next;
      end if;
   end Remove_Element;

   function Exists(data : Element_Type) return Boolean is
      temp : access Node := Beginning;
   begin
      while temp /= null or temp.all.Value /= data loop
         temp := temp.Next;
      end loop;
      if temp = null then
         return false;
      end if;
      return true;
   end Exists;
begin
   Beginning.all.Next := Last;
end Linked_List;

Linked_List.ads :

generic
   type Element_Type is private;
package Linked_List is 
   function Get_First_Element return Element_Type;
   function Get_Last_Element return Element_Type;
   procedure Add_Element(data : Element_Type);
   procedure Remove_Element(data : Element_Type);
   function Exists(data : Element_Type) return Boolean;
private
   type Node is 
      record
            Value : Element_Type;
            Next : access Node;
      end record;
   Beginning : access Node;
   Last : access Node;
end Linked_List;

Does two files are compiling fine. Here is my main procedure:

With Ada.Text_IO; use Ada.Text_IO;
with Linked_List;
procedure Main is
   package List is new Linked_List(Element_Type => Integer);
   lst : List;
begin

   for i in -5..5 loop
      lst.Add_Element(i);
   end loop;
   lst.Remove_Element(1);
   Put_Line(lst.Exists(2));
end Main;

This is where I'm facing a problem. Here are the errors which the compiler is giving me:

main.adb:5:10: subtype mark required in this context
main.adb:5:10: found "List" declared at line 4
main.adb:5:14: incorrect constraint for this kind of type
main.adb:9:07: invalid prefix in selected component "lst"
main.adb:11:04: invalid prefix in selected component "lst"
main.adb:12:13: invalid prefix in selected component "lst"

I can't understand this error:

main.adb:5:10: subtype mark required in this context

I can understand what the other errors are telling me.

Edit: I fixed part of the code and I got new error messages, everything is updated.


Solution

  • Packages are essentially namespaces, not classes. As such, you can't create an object (instance) of that package, which does not export any types.

    So what you have declared is something rather like a singleton : there can only be one of it (per generic instantiation), in your case, called List. And List exports subprograms you can use.

    So delete the declaration lst : List; and call the subprograms directly, List.Add_Element(i); and your example should work.

    If you need more linked lists, you can instantiate the generic as many times as you want. The list you are using in each call is determined by the instantiated package name.


    If you wanted to create objects of a type declared in the package, you would have to declare the type in the package; adding the line type Node is private; in the public part is all you need to do; though type Node_Acc is access node; is often useful too - then update your declarations of Beginning,Last to be of this type.

    Then each subprogram needs to know which Node they operate on; so they need a Node as an argument, for example function Get_First_Element(this : Node) return Element_Type;

    Now you can declare objects of type Node and pass them as arguments. If the record is a tagged record you can use either function(argument) or object.method notation, whichever makes the program easier to understand.

    -- package
    type Node is tagged private;
    private
    type Node is tagged record ...;
    
    -- client code
        Head : List.Node;
        ...
        Add_Element(Head,1);
        Head.Add_Element(2);