user9483537
user9483537

Reputation:

Ada record with constant access-to-object-of-parent-type

I recently started learning Ada. I want to see if there's a possibility in creating a Boost::Statechart-like framework in Ada. To do this I need a record structure with a constant access-to-object-of-parent-type component, like a tree node that statically points to another tree node, and the parent pointer must not be changed at all times. Something like this:

-- Not working sample

type Node_T is record
    Parent : constant access Node_T;
    -- error: constant components are not permitted
end record;
-- I wish to create objects of this type like this

Top_Node : Node_T (null);
Child1_Node : Node_T (Top_Node'Access);
Child2_Node : Node_T (Top_Node'Access);

It seems that constant member fields are not supported in Ada. So I resorted to using access discriminants:

-- Not working sample

type Node_T (Parent : access Node_T) is null record;
-- error: type declaration cannot refer to itself

However, using named-access-type as discriminant works

type Node_T;
type Ref_Node_T is access all Node_T;

type Node_T (Parent : Ref_Node_T) is null record;

However, from what I learned this causes the life-time of Node_T objects to be bound to that of a Ref_Node_T object, rather than another parent Node_T object. Is this true?

Are there any better ways of implementing what I need?

Upvotes: 1

Views: 288

Answers (2)

Shark8
Shark8

Reputation: 4198

An alternate alternate solution for FSM is to use enumerations and arrays, and if you're going to need more than one, generic.

Generic
   Type State is (<>); -- Any discrete type.
   Type Event is (<>);
Package Finite_State_Machine_Domain is
   Type Domain is Array(State, Event) of State;
   
   Generic
     Start,
     Error : State;
   Package Finite_State_Machine is
      Type State_Machine is private;
      Function  Create    (State_Map : Domain)            return State_Machine;
      Function  Get_State (Object : in     State_Machine) return State;
      Procedure Send_Event(Object : in out State_Machine; Transition : in Event);
   Private
      Type State_Machine is record
         Current   : State  := Start;
         State_Map : Domain := (Others => Error);
      End record;
   End Finite_State_Machine;
End Finite_State_Machine_Domain;

Package Body Finite_State_Machine_Domain is
   Package Body Finite_State_Machine is

      Function  Create (State_Map : Domain) return State_Machine is
       ( State_Machine'(State_Map => State_Map, Others => <>) );

      Function  Get_State (Object : in     State_Machine) return State is
       ( Object.Current );

      Procedure Send_Event(Object : in out State_Machine; Transition : in Event) is
      Begin
         if Object.Current /= Error then
            Object.Current:= Object.State_Map(Object.Current, Transition);
         end if;
      End Send_Event;

   End Finite_State_Machine;
End Finite_State_Machine_Domain;

Upvotes: 0

Jim Rogers
Jim Rogers

Reputation: 5021

An alternate approach to creating a finite state machine is described in https://www.sigada.org/ada_letters/june2000/sanden.pdf This solution uses a combination of protected objects and tasks to implement the finite state machine.

Upvotes: 1

Related Questions