2

I'm attempting to wrap a hashed map with a protected object so it can be accessed via a multiple tasks. I want the procedures on the protected type to be available but it would be nice to move the hash map and element record definition into the packages private section.

Example code here:

package Thing_Protected is

   type Thing_Info is record
      Key : Ada.Strings.Unbounded.Unbounded_String;
      Counter_Value : Natural := 0;
   end record;

   package Thing_Info_Maps is new Ada.Containers.Hashed_Maps
      (Key_Type => Ada.Strings.Unbounded.Unbounded_String,
      Element_Type => Thing_Info,
      Hash => Ada.Strings.Unbounded.Hash,
      Equivalent_Keys => Ada.Strings.Unbounded."=");

   protected type Thing is
      procedure Increment (Key : String);
      procedure Another_Thing (Key : String);
   private
      Thing_Map : Thing_Info_Maps.Map;
   end Thing;

private

   -- move Thing_Info, Thing_info_maps into here.

end Thing_Protected;

I've tried defining Thing_Info as a private type.. but I'm not sure how I would define the Thing_Info_Maps package as private but still access it from the protected object type.

So really I wouldn't find trying to find a way to get something like this:

package Thing_Protected is

   type Thing_Info is private;
   package Thing_Info_Maps is private;

   protected type Thing is
      procedure Increment (Key : String);
      procedure Another_Thing (Key : String);
   private
      Thing_Map : Thing_Info_Maps.Map;  --  <<- how would we know about .Map??
   end Thing;

private

   type Thing_Info is record
      Key : Ada.Strings.Unbounded.Unbounded_String;
      Counter_Value : Natural := 0;
   end record;

   package Thing_Info_Maps is new Ada.Containers.Hashed_Maps
      (Key_Type => Ada.Strings.Unbounded.Unbounded_String,
      Element_Type => Thing_Info,
      Hash => Ada.Strings.Unbounded.Hash,
      Equivalent_Keys => Ada.Strings.Unbounded."=");

end Thing_Protected;
Nick Sonneveld
  • 3,356
  • 6
  • 39
  • 48
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Oct 11 '13 at 01:46
  • I guess now it's not as obvious that it's ada related. Especially since of the top 15 voted questions tagged 'ada', only one didn't have Ada in the title. – Nick Sonneveld Oct 11 '13 at 02:20
  • I'll take care of that. – John Saunders Oct 11 '13 at 04:15
  • I just looked at the first page of [tag:ada] questions, and only one had the tag in the title in a manner that was not "organic": http://stackoverflow.com/questions/9045646/ada-how-can-you-check-if-an-element-belongs-to-one-subtype-or-another. I fixed the title. If you read the linked article, you'll see that it's not a problem to have the tag somewhere in the title. The problem is where the tag is added to a perfectly good title in order to characterize the question in a way that tags already do. – John Saunders Oct 11 '13 at 04:17
  • Fair enough, I added the word 'Ada' a bit more organically to the title. My issue was that if you remove 'Ada' altogether, the question looks like a very general programming question when it was really about Ada. – Nick Sonneveld Oct 11 '13 at 04:46
  • The tags take care of informing people that the question is about Ada. And they do that in a much more powerful way that putting "Ada" in the title. For instance, users can indicate [tag:ada] as a favorite tag, so that Ada questions will be highlighted. – John Saunders Oct 11 '13 at 05:00
  • Since one can set up an RSS feed for a tag, that's how I, among others, are notified when an 'Ada' question shows up on SO. – Marc C Oct 11 '13 at 14:43

3 Answers3

7

With Ada 2005, you can use a protected interface:

package Thing_Protected is

   type Thing is protected interface;

   procedure Increment     (Object : in out Thing; Key : String) is abstract;
   procedure Another_Thing (Object : in out Thing; Key : String) is abstract;

   -- As the implementation type is private, we need a
   -- factory method which returns an instance of the
   -- implementation type:
   function Create return Thing'Class;

private

   type Thing_Info is record
      Key : Ada.Strings.Unbounded.Unbounded_String;
      Counter_Value : Natural := 0;
   end record;

   package Thing_Info_Maps is new Ada.Containers.Hashed_Maps
      (Key_Type => Ada.Strings.Unbounded.Unbounded_String,
      Element_Type => Thing_Info,
      Hash => Ada.Strings.Unbounded.Hash,
      Equivalent_Keys => Ada.Strings.Unbounded."=");

   protected type Thing_Impl is new Thing with
      overriding procedure Increment (Key : String);
      overriding procedure Another_Thing (Key : String);
   private
      Thing_Map : Thing_Info_Maps.Map;
   end Thing_Impl;

end Thing_Protected;
Simon Wright
  • 25,108
  • 2
  • 35
  • 62
flyx
  • 35,506
  • 7
  • 89
  • 126
  • This is a great answer but I'm not entirely sure how to implement the Create function. I've managed to get it working by returning an access to a Thing'Class. Trying to return a Thing'Class gives me interesting errors like "initialization of limited object requires aggregate or function call" or "expected type "Thing_Impl" defined at ... , found a composite type" Would this be because synchronised interfaces are limited types so so cannot be copied? – Nick Sonneveld Oct 14 '13 at 00:06
  • Ah, I think I figured it out. I need to use an extended return statement: http://www.adacore.com/adaanswers/gems/ada-gem-10/ – Nick Sonneveld Oct 14 '13 at 00:29
  • Protected type are inherently limited, so are protected interfaces. You can definitely get it to work without an extended return statement, but as I don't know what you tried, I cannot tell you what you did wrong. – flyx Oct 14 '13 at 07:02
  • This felt like something that should be answered via a stackoverflow question rather than through comments: http://stackoverflow.com/questions/19370607/returning-a-limited-type-in-ada – Nick Sonneveld Oct 14 '13 at 22:59
2

how would we know about .Map??

How about something like this?

Generic
    type Thing_Info is private;
    with package Thing_Info_Maps is new Ada.Containers.Hashed_Maps(
            Key_Type        => Ada.Strings.Unbounded.Unbounded_String,
            Element_Type    => Thing_Info,
            Hash            => Ada.Strings.Unbounded.Hash,
            Equivalent_Keys => Ada.Strings.Unbounded."=");
Package INFO is

    protected type Thing is
        procedure Increment     (Key : String);
        procedure Another_Thing (Key : String);
    private
        -- BEHOLD THE POWER OF GENERICS!!
        Thing_Map : Thing_Info_Maps.Map;
    end Thing;

Private
    -- PRIVATE STUFF
End INFO;
Shark8
  • 4,095
  • 1
  • 17
  • 31
  • Isn't that still putting the hashed_map in the package interface? I guess I wanted to have Increment() and Another_Thing() publicly available but a user shouldn't need to know that I'm using a hashmap behind the scenes. – Nick Sonneveld Oct 11 '13 at 04:44
  • It is; I suppose you could make `Thing` itself into a private type and have `procedure Increment( Item : in out Thing; Key : String )` in the spec with renaming/wrapping in the body OR have a private type `Thing_Map` which is a subtype rename of `Thing_Info_Maps`... – Shark8 Oct 11 '13 at 17:19
2

Do the users of this package need to know that there's a protected type in there? if not, you could declare a (tagged) type in the visible part of the spec with primitive subprograms to match:

package Thing_Protected is

   type Thing is tagged limited private;
   procedure Increment (This : in out Thing; Key : String);
   procedure Another_Thing (This : in out Thing; Key : String);

private

   type Thing_Info is record
      Key : Ada.Strings.Unbounded.Unbounded_String;
      Counter_Value : Natural := 0;
   end record;

   package Thing_Info_Maps is new Ada.Containers.Hashed_Maps
     (Key_Type => Ada.Strings.Unbounded.Unbounded_String,
      Element_Type => Thing_Info,
      Hash => Ada.Strings.Unbounded.Hash,
      Equivalent_Keys => Ada.Strings.Unbounded."=");

   protected type Thing_Imp is
      procedure Increment (Key : String);
      procedure Another_Thing (Key : String);
   private
      Thing_Map : Thing_Info_Maps.Map;
   end Thing_Imp;

   type Thing is tagged limited record
      Imp : Thing_Imp;
   end record;

end Thing_Protected;

with body like

package body Thing_Protected is

   procedure Increment (This : in out Thing; Key : String) is
   begin
      This.Imp.Increment (Key);
   end Increment;

   procedure Another_Thing (This : in out Thing; Key : String) is
   begin
      This.Imp.Another_Thing (Key);
   end Another_Thing;

   protected body Thing_Imp is
      procedure Increment (Key : String) is
         N : constant Ada.Containers.Count_Type := Thing_Map.Length;
      begin
         null;
      end Increment;
      procedure Another_Thing (Key : String) is
      begin
         null;
      end Another_Thing;
   end Thing_Imp;

end Thing_Protected;
Simon Wright
  • 25,108
  • 2
  • 35
  • 62