comp.lang.ada
 help / color / mirror / Atom feed
* Design of cross referring types/classes and proper usage of containers
@ 2015-08-03 16:08 Serge Robyns
  2015-08-03 16:14 ` Serge Robyns
  2015-08-03 16:22 ` Dmitry A. Kazakov
  0 siblings, 2 replies; 17+ messages in thread
From: Serge Robyns @ 2015-08-03 16:08 UTC (permalink / raw)


I've a design issue with regards to what is the best if not ideal approach in building types or classes that refer to each other and could be aggregates.

Lets use an example  I've the following entity:

   type T_Client is tagged record  -- will be mapped a table
      Id         : Integer := 0;
      First_Name : T_Client_Name := T_Client_Name (P_Empty_String);
      Last_Name  : T_Client_Name := T_Client_Name (P_Empty_String);
   end record;

This is to keep track of client info.

I've the following other entity amongst others.

   type T_Subscription is tagged record  -- will be mapped to a table
      Name    : T_Subscriptiont_Name := No_Subscription_Name;
      Product : T_Product_Name := No_Product_Name;
      Client  : T_Client := No_Client;   -- Could also be of the same type T_Client.Id, used in different approach.
      Date    : Ada.Calendar.Time := GNAT.Calendar.No_Time;
   end record;

And I've other entities as well that do have similar relationships.

The application is keeping parts of the (static) data in memory but eventually all the data will be retrieved and stored into a database.  I'm planning to use a design pattern (bridge or others) to implemnent this step.

However, I'm wondering what would be the best Ada approach to have these objects interacting, i.e, referring to each other.  Currently I'm using the db approach, which means I use keys to search in various independant containers.

But why not for example, Client that could have an Ada container of T_Subscriptions.  This container could be either the object itself or a reference (access) or why not a Cursor to another Container containing all subscriptions.  The same applies for the client in the subscription.

And I've a few other of such entities/cases.

I'm all ears to the audience experience in this matter.

Regards,
Serge

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Design of cross referring types/classes and proper usage of containers
  2015-08-03 16:08 Design of cross referring types/classes and proper usage of containers Serge Robyns
@ 2015-08-03 16:14 ` Serge Robyns
  2015-08-03 20:17   ` Georg Bauhaus
  2015-08-03 16:22 ` Dmitry A. Kazakov
  1 sibling, 1 reply; 17+ messages in thread
From: Serge Robyns @ 2015-08-03 16:14 UTC (permalink / raw)


On Monday, 3 August 2015 18:08:17 UTC+2, Serge Robyns  wrote:
> I've a design issue with regards to what is the best if not ideal approach in building types or classes that refer to each other and could be aggregates.
> 
> Lets use an example  I've the following entity:
> 
>    type T_Client is tagged record  -- will be mapped a table
>       Id         : Integer := 0;
>       First_Name : T_Client_Name := T_Client_Name (P_Empty_String);
>       Last_Name  : T_Client_Name := T_Client_Name (P_Empty_String);
>    end record;
> 
> This is to keep track of client info.
> 
> I've the following other entity amongst others.
> 
>    type T_Subscription is tagged record  -- will be mapped to a table
>       Name    : T_Subscriptiont_Name := No_Subscription_Name;
>       Product : T_Product_Name := No_Product_Name;
>       Client  : T_Client := No_Client;   -- Could also be of the same type T_Client.Id, used in different approach.
>       Date    : Ada.Calendar.Time := GNAT.Calendar.No_Time;
>    end record;
> 
> And I've other entities as well that do have similar relationships.
> 
> The application is keeping parts of the (static) data in memory but eventually all the data will be retrieved and stored into a database.  I'm planning to use a design pattern (bridge or others) to implemnent this step.
> 
> However, I'm wondering what would be the best Ada approach to have these objects interacting, i.e, referring to each other.  Currently I'm using the db approach, which means I use keys to search in various independant containers.
> 
> But why not for example, Client that could have an Ada container of T_Subscriptions.  This container could be either the object itself or a reference (access) or why not a Cursor to another Container containing all subscriptions.  The same applies for the client in the subscription.
> 
> And I've a few other of such entities/cases.
> 
> I'm all ears to the audience experience in this matter.
> 
> Regards,
> Serge

And I forgot to mention, I'm trying to avoid access as much as possible, where it makes sense.  In my C-days, I would have independant containers and use references/pointers.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Design of cross referring types/classes and proper usage of containers
  2015-08-03 16:08 Design of cross referring types/classes and proper usage of containers Serge Robyns
  2015-08-03 16:14 ` Serge Robyns
@ 2015-08-03 16:22 ` Dmitry A. Kazakov
  2015-08-04 11:43   ` Serge Robyns
  1 sibling, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2015-08-03 16:22 UTC (permalink / raw)


On Mon, 3 Aug 2015 09:08:15 -0700 (PDT), Serge Robyns wrote:

> I've a design issue with regards to what is the best if not ideal approach
> in building types or classes that refer to each other and could be
> aggregates.
> 
> Lets use an example  I've the following entity:
> 
>    type T_Client is tagged record  -- will be mapped a table
>       Id         : Integer := 0;
>       First_Name : T_Client_Name := T_Client_Name (P_Empty_String);
>       Last_Name  : T_Client_Name := T_Client_Name (P_Empty_String);
>    end record;
> 
> This is to keep track of client info.
> 
> I've the following other entity amongst others.
> 
>    type T_Subscription is tagged record  -- will be mapped to a table
>       Name    : T_Subscriptiont_Name := No_Subscription_Name;
>       Product : T_Product_Name := No_Product_Name;
>       Client  : T_Client := No_Client;   -- Could also be of the same type T_Client.Id, used in different approach.
>       Date    : Ada.Calendar.Time := GNAT.Calendar.No_Time;
>    end record;
> 
> And I've other entities as well that do have similar relationships.

When aggregation does not work, which is the case when relationships are
complex, you keep them outside. You create maps

   Client to [not null access] Subscription
   Subscription to [not null access] Client

etc. And search the maps if you have one and need another. For the map you
can use hash or binary searched container.

Note that aggregation is fragile. If you have a suspicion that
relationships may go chaotic, don't aggregate.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Design of cross referring types/classes and proper usage of containers
  2015-08-03 16:14 ` Serge Robyns
@ 2015-08-03 20:17   ` Georg Bauhaus
  0 siblings, 0 replies; 17+ messages in thread
From: Georg Bauhaus @ 2015-08-03 20:17 UTC (permalink / raw)


On 03.08.15 18:14, Serge Robyns wrote:
> And I forgot to mention, I'm trying to avoid access as much as possible, where it makes sense.  In my C-days, I would have independant containers and use references/pointers.

Another technique will model the mutual relationship in a third
type dedicated to the purpose.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Design of cross referring types/classes and proper usage of containers
  2015-08-03 16:22 ` Dmitry A. Kazakov
@ 2015-08-04 11:43   ` Serge Robyns
  2015-08-04 12:13     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 17+ messages in thread
From: Serge Robyns @ 2015-08-04 11:43 UTC (permalink / raw)


On Monday, 3 August 2015 18:22:20 UTC+2, Dmitry A. Kazakov  wrote:
> 
> When aggregation does not work, which is the case when relationships are
> complex, you keep them outside. You create maps
> 
>    Client to [not null access] Subscription
>    Subscription to [not null access] Client
> 
> etc. And search the maps if you have one and need another. For the map you
> can use hash or binary searched container.
> 
> Note that aggregation is fragile. If you have a suspicion that
> relationships may go chaotic, don't aggregate.
> 
> --

Thank you for the advice.  You confirm my intuition, which also makes the implementation more in 1 to 1 with the storage data model, as the db will be used for other purposes as reporting.  Today, I'm indeed using map containers for most of these.

Is there any point of attention when using access variables to containers?  Any risk of dangling pointers because of operations on the elements of the map (updates)?

Regards,
Serge

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Design of cross referring types/classes and proper usage of containers
  2015-08-04 11:43   ` Serge Robyns
@ 2015-08-04 12:13     ` Dmitry A. Kazakov
  2015-08-04 19:00       ` Serge Robyns
  0 siblings, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2015-08-04 12:13 UTC (permalink / raw)


On Tue, 4 Aug 2015 04:43:25 -0700 (PDT), Serge Robyns wrote:

> Is there any point of attention when using access variables to containers? 
> Any risk of dangling pointers because of operations on the elements of the
> map (updates)?

When objects are clearly scoped or known to be permanent or allocated in an
arena with a defined life time there is nothing to worry about.

In all other cases I use reference counted objects with hard references to
them within the maps. In some rare cases it could be weak references as
well.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Design of cross referring types/classes and proper usage of containers
  2015-08-04 12:13     ` Dmitry A. Kazakov
@ 2015-08-04 19:00       ` Serge Robyns
  2015-08-04 19:20         ` Jeffrey R. Carter
                           ` (3 more replies)
  0 siblings, 4 replies; 17+ messages in thread
From: Serge Robyns @ 2015-08-04 19:00 UTC (permalink / raw)


And I've a final question based on the advise.

Given static (immutable data) one one hand and dynamic data (changed during the execution) on the other hand; stored in various containers.  What is actually the best approach? Shall I Storing the full element of objects or references created through new T_xyz?

If I want to use an access variables in the first method, do I need to pass an aliased type?




^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Design of cross referring types/classes and proper usage of containers
  2015-08-04 19:00       ` Serge Robyns
@ 2015-08-04 19:20         ` Jeffrey R. Carter
  2015-08-04 20:27         ` Randy Brukardt
                           ` (2 subsequent siblings)
  3 siblings, 0 replies; 17+ messages in thread
From: Jeffrey R. Carter @ 2015-08-04 19:20 UTC (permalink / raw)


On 08/04/2015 12:00 PM, Serge Robyns wrote:
> And I've a final question based on the advise.
> 
> Given static (immutable data) one one hand and dynamic data (changed during the execution) on the other hand; stored in various containers.  What is actually the best approach? Shall I Storing the full element of objects or references created through new T_xyz?
> 
> If I want to use an access variables in the first method, do I need to pass an aliased type?

Your problem does not need access types, and will be clearer and simpler without
them.

You could have maps:

(client ID)       -> (client info)
(subscription ID) -> (subscription info)

Client info may contain subscription IDs, and subscription info may contain
client IDs. If you have one and not another, you use the ID to obtain the info.

-- 
Jeff Carter
"Have you gone berserk? Can't you see that that man is a ni?"
Blazing Saddles
38


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Design of cross referring types/classes and proper usage of containers
  2015-08-04 19:00       ` Serge Robyns
  2015-08-04 19:20         ` Jeffrey R. Carter
@ 2015-08-04 20:27         ` Randy Brukardt
  2015-08-04 21:21         ` Simon Wright
  2015-08-05  7:37         ` Dmitry A. Kazakov
  3 siblings, 0 replies; 17+ messages in thread
From: Randy Brukardt @ 2015-08-04 20:27 UTC (permalink / raw)


"Serge Robyns" <serge.robyns@gmail.com> wrote in message 
news:3341271b-4926-40cb-a9aa-660522d56f24@googlegroups.com...
>And I've a final question based on the advise.
>
>Given static (immutable data) one one hand and dynamic data (changed during 
>the
> execution) on the other hand; stored in various containers.  What is 
> actually the
> best approach? Shall I Storing the full element of objects or references 
> created
> through new T_xyz?

It obviously depends. Surely the first choice is to put the data objects 
directly into the container. That lets the container do all of the storage 
management (especially nice for indefinite types like T'Class); it's far 
more likely to do it correctly than you would. (the chances of a bug in your 
memory management code is much higher than the chances of a bug in a 
container implementation).

I'd only put access types into a container if those access types exist for 
some other reason in your program.

>If I want to use an access variables in the first method, do I need to pass 
>an aliased type?

???

Ada doesn't have aliased types ("aliased" is a property of an object [inc. 
components and parameters]).

                                Randy.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Design of cross referring types/classes and proper usage of containers
  2015-08-04 19:00       ` Serge Robyns
  2015-08-04 19:20         ` Jeffrey R. Carter
  2015-08-04 20:27         ` Randy Brukardt
@ 2015-08-04 21:21         ` Simon Wright
  2015-08-08 11:25           ` Serge Robyns
  2015-08-05  7:37         ` Dmitry A. Kazakov
  3 siblings, 1 reply; 17+ messages in thread
From: Simon Wright @ 2015-08-04 21:21 UTC (permalink / raw)


Serge Robyns <serge.robyns@gmail.com> writes:

> Shall I Storing the full element of objects or references created
> through new T_xyz

The objects should be limited, in Ada terms; you don't want a copy of a
subscription in a client object (in general; I guess if subscriptions
have no other relationships .. well, no, a <thing that is subscribed to>
- say, Mailing_List - will in general have many subscribers, and a
client will have many subscriptions). In general I'd keep Clients as
elements in a Map keyed by client_ID, likewise Mailing_Lists. The
limited object in the Map *is* the Client, you can't copy it out and
risk confusing the copied info with the thing itself.

I'd try to implement a Subscription as a record containing a client_ID
and a mailing_list_ID and any supplementary data (renewal date, discount
rate ...), and keep them in a Subscription container (classic database
stuff). This does leave you to work out how to get efficient access from
a specific Client to all the Mailing_Lists that they subscribe to, and
vice versa, and you might want to optimise a bit.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Design of cross referring types/classes and proper usage of containers
  2015-08-04 19:00       ` Serge Robyns
                           ` (2 preceding siblings ...)
  2015-08-04 21:21         ` Simon Wright
@ 2015-08-05  7:37         ` Dmitry A. Kazakov
  2015-08-05 17:51           ` Serge Robyns
  3 siblings, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2015-08-05  7:37 UTC (permalink / raw)


On Tue, 4 Aug 2015 12:00:28 -0700 (PDT), Serge Robyns wrote:

> Given static (immutable data) one one hand and dynamic data (changed
> during the execution) on the other hand; stored in various containers. 
> What is actually the best approach? Shall I Storing the full element of
> objects or references created through new T_xyz?

That depends on the semantics of mutators. If the semantics is referential,
e.g. you change the object in one place and all logical references get
aware of the change, the only way (that does not involve global variables
and distributed overhead) is having physical references.

Things like MVC require referential semantics.

> Shall I Storing the full element of
> objects or references created through new T_xyz?

You could have a constructing function that hides ugly allocator. E.g. when
using strong references you might have:

    function Create (...) return Handle;

which internally allocates some private limited object the tagged Handle
points to. Handle can be copied around and stored into a container. [*]

> If I want to use an access variables in the first method, do I need to
> pass an aliased type?

Aliased objects, yes. However some types have only aliased instances.

----------------
* Yet another possible reason against using aggregation is that you cannot
put limited members into non-limited records, for obvious reasons. But a
handle is non-limited.

E.g. in GtkAda the widget type is non-limited. The effect is that you
cannot put a task or a protected object or a limited container into a
widget. In Ada "limitness" is transitive upon inheritance.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Design of cross referring types/classes and proper usage of containers
  2015-08-05  7:37         ` Dmitry A. Kazakov
@ 2015-08-05 17:51           ` Serge Robyns
  2015-08-05 19:21             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 17+ messages in thread
From: Serge Robyns @ 2015-08-05 17:51 UTC (permalink / raw)


On Wednesday, 5 August 2015 09:37:20 UTC+2, Dmitry A. Kazakov  wrote:
> On Tue, 4 Aug 2015 12:00:28 -0700 (PDT), Serge Robyns wrote:
> 
> > Given static (immutable data) one one hand and dynamic data (changed
> > during the execution) on the other hand; stored in various containers. 
> > What is actually the best approach? Shall I Storing the full element of
> > objects or references created through new T_xyz?
> 
> That depends on the semantics of mutators. If the semantics is referential,
> e.g. you change the object in one place and all logical references get
> aware of the change, the only way (that does not involve global variables
> and distributed overhead) is having physical references.

I've indeed two instances of such objects so far.  This allows me to use a "setter" like Obj.Change (Value), once I've pulled them from on of the containers (through indirection).  (BTW I do love the Ada 2012 changes to containers.)  In my first attempt, I stored them in their referring object through an access type (for speed), now I'm storing their key in their referring object and use it to find them in their respective containers.  I've been thinking on returning a Cursor but then I'm exposing the implementation and require to put the container definition into the specification package of the package building the these containers.

My end goal is to use a Proxy pattern, allowing the data to be retrieved from a XML file (ideal for test automation) or from a database (in production mode).  In the case of the XML file, the whole data gets loaded at once into containers, whereas for a database approach, specific SQL statements will retrieve the data by these proxies.  The users of the objects shouldn't notice the implementation.

> 
> Things like MVC require referential semantics.
> 
> > Shall I Storing the full element of
> > objects or references created through new T_xyz?
> 
> You could have a constructing function that hides ugly allocator. E.g. when
> using strong references you might have:
> 
>     function Create (...) return Handle;
> 
> which internally allocates some private limited object the tagged Handle
> points to. Handle can be copied around and stored into a container. [*]
> 

Limited objects is one of these things I'm struggling getting my head around.  I will need to (re)read about it to fully understand their purpose as for now I perceive them as a pain.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Design of cross referring types/classes and proper usage of containers
  2015-08-05 17:51           ` Serge Robyns
@ 2015-08-05 19:21             ` Dmitry A. Kazakov
  2015-08-06  7:00               ` Georg Bauhaus
  0 siblings, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2015-08-05 19:21 UTC (permalink / raw)


On Wed, 5 Aug 2015 10:51:36 -0700 (PDT), Serge Robyns wrote:

> Limited objects is one of these things I'm struggling getting my head
> around.  I will need to (re)read about it to fully understand their
> purpose as for now I perceive them as a pain.

Limited object is an object with an identity (inside its value). That is
why you cannot copy it. It is neither a pain or bliss, just an aspect of
design. Some things have identity some don't, you choose the type
appropriately.

There are some obscure cases when Ada breaks this abstraction, e.g. in the
limited return, but nothing to worry about much.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Design of cross referring types/classes and proper usage of containers
  2015-08-05 19:21             ` Dmitry A. Kazakov
@ 2015-08-06  7:00               ` Georg Bauhaus
  0 siblings, 0 replies; 17+ messages in thread
From: Georg Bauhaus @ 2015-08-06  7:00 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote:
> On Wed, 5 Aug 2015 10:51:36 -0700 (PDT), Serge Robyns wrote:
> 
>> Limited objects is one of these things I'm struggling getting my head
>> around.  I will need to (re)read about it to fully understand their
>> purpose as for now I perceive them as a pain.
> 
> Limited object is an object with an identity (inside its value). That is
> why you cannot copy it. It is neither a pain or bliss, just an aspect of
> design. Some things have identity some don't, you choose the type
> appropriately.

Invariable identity may be more suggestive.
Like Earth and Mars: you may change them,
but cannot change Mars to be like Earth
and then have it take Earth's place. That is,
Mars stays Mars no matter how you'd change it.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Design of cross referring types/classes and proper usage of containers
  2015-08-04 21:21         ` Simon Wright
@ 2015-08-08 11:25           ` Serge Robyns
  2015-08-09  3:11             ` Randy Brukardt
  0 siblings, 1 reply; 17+ messages in thread
From: Serge Robyns @ 2015-08-08 11:25 UTC (permalink / raw)


As a follow-up on this discussion, I'm trying to have one of my containers containing the subscriptions but whereas I've a function returning the access to it in order to allow changes to it, through class procedures, not direct assignments.  This works if the container is storing access values, allocated through new T_Subscription.  When reading about Ada 2012 concept of of Reference_Type, I was trying to alter the container to store the T_Subscription without using access types.  However it does fail with compiler errors.

Here is the code snippet:

   package Subscription_Map is new Ada.Containers.Ordered_Maps (Key_Type     => T_Subscription_Name,
                                                                Element_Type => T_Subscription);


   Subscriptions          : aliased Subscription_Map.Map;

																
   function Get_Subscription
     (Subscription_Name : in T_Subscription_Name)
      return T_Subscription_Access is
      Cursor : Subscription_Map.Cursor;
   begin
      Cursor := Subscriptions.Find (Subscription_Name);
      if Cursor = Subscription_Map.No_Element then
         return null;
      else
         return T_Subscription_Access (Subscriptions.Reference (Cursor));
      end if;
   end Get_Subscription;

And the compiler moans on the return in the else part =>
ambiguous operand in conversion
possible interpretation at a-coorma.ads:104, instance at line 25
possible interpretation at a-coorma.ads:113, instance at line 25


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Design of cross referring types/classes and proper usage of containers
  2015-08-08 11:25           ` Serge Robyns
@ 2015-08-09  3:11             ` Randy Brukardt
  2015-08-09 13:33               ` Serge Robyns
  0 siblings, 1 reply; 17+ messages in thread
From: Randy Brukardt @ 2015-08-09  3:11 UTC (permalink / raw)


"Serge Robyns" <serge.robyns@gmail.com> wrote in message 
news:34d1bef3-5d7b-4420-8256-7227d5792a13@googlegroups.com...

...
>      return T_Subscription_Access (Subscriptions.Reference (Cursor));
...
>And the compiler moans on the return in the else part =>
>ambiguous operand in conversion
>possible interpretation at a-coorma.ads:104, instance at line 25
>possible interpretation at a-coorma.ads:113, instance at line 25

The operand of a type conversion has to be resolvable without using any 
context. But I'd expect that to be OK in this case, as the Cursor should 
disambiuate it.

Probably the real problem is that Reference doesn't return an access but 
rather a "Reference_Type" which has the "Implicit_Dereference" aspect. The 
compiler can't know whether or not to use that aspect, as there is no 
context, so it tries both and gives this error. (Not the clearest error 
message ever, but Ada resolution rarely leads to great error messages, since 
it is just a yes or no answer, and the number of reasons for "no" can seem 
infinite.)

Write out the reference to the discriminant of the Reference_Type and this 
problem ought to go away. (I can't try it since you didn't post a complete 
program.)

    return T_Subscription_Access (Subscriptions.Reference (Cursor).Element);

However, I think you'll find that you get a different error here. The 
containers are designed such that you can only get a short-lived access into 
them, and here you are assigning this into a long-lived access type. Thus 
you ought to get an accessibility error.

I'd probably try to avoid returning an access at all; for reading purposes, 
you can just return a copy of the subscription; and for writing purposes I'd 
suggest having the Subscription package do that (that is, it would contain 
some procedures for altering particular Subscriptions).

If that's too much disruption for your design, you can try going over to the 
dark side and use an anonymous access return type. That will push the 
accessibility check to run-time; so long as the caller doesn't try to store 
the resulting access, they ought to be able to use it just as you can use 
Reference. OTOH, if they try to put into a long-lived type, Program_Error 
will be raised by the return statement. In this case, you do not want there 
to be a type T_Subscription_Access, as that would encourage clients to use 
it (causing the exception).

This would look like:

   function Get_Subscription
     (Subscription_Name : in T_Subscription_Name)
      return access T_Subscription is
      Cursor : Subscription_Map.Cursor;
   begin
      Cursor := Subscriptions.Find (Subscription_Name);
      if Cursor = Subscription_Map.No_Element then
         return null;
      else
         return Subscriptions.Reference (Cursor).Element;
      end if;
   end Get_Subscription;

You could also return the Reference_Type itself (slightly safer, as clients 
would get a compile-time failure). But that would messy (probably you'd want 
to make it a private type and then derive it from the Reference_Type of the 
instance). I can show you what I mean on Monday if you can't figure it out 
yourself (I'll have to code up something to see if it actually works).

In any case, the point is that if you are going to eliminate the access 
types, you really need to eliminate all of them! Leaving some is 
problematical.

                                            Randy.



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Design of cross referring types/classes and proper usage of containers
  2015-08-09  3:11             ` Randy Brukardt
@ 2015-08-09 13:33               ` Serge Robyns
  0 siblings, 0 replies; 17+ messages in thread
From: Serge Robyns @ 2015-08-09 13:33 UTC (permalink / raw)


On Sunday, 9 August 2015 05:11:07 UTC+2, Randy Brukardt  wrote:
> I'd probably try to avoid returning an access at all; for reading purposes, 
> you can just return a copy of the subscription; and for writing purposes I'd 
> suggest having the Subscription package do that (that is, it would contain 
> some procedures for altering particular Subscriptions).
> 
> If that's too much disruption for your design, you can try going over to the 
> dark side and use an anonymous access return type. That will push the 
> accessibility check to run-time; so long as the caller doesn't try to store 
> the resulting access, they ought to be able to use it just as you can use 
> Reference. OTOH, if they try to put into a long-lived type, Program_Error 
> will be raised by the return statement. In this case, you do not want there 
> to be a type T_Subscription_Access, as that would encourage clients to use 
> it (causing the exception).
> 
> This would look like:
> 
>    function Get_Subscription
>      (Subscription_Name : in T_Subscription_Name)
>       return access T_Subscription is
>       Cursor : Subscription_Map.Cursor;
>    begin
>       Cursor := Subscriptions.Find (Subscription_Name);
>       if Cursor = Subscription_Map.No_Element then
>          return null;
>       else
>          return Subscriptions.Reference (Cursor).Element;
>       end if;
>    end Get_Subscription;
>

This was a very precious hint.  It helped me to solve the problem with some trial and errors on the real code.  I had to resolve it also for a cursor, that behaves slightly different, as I'm also using Index, but there the RM was for once helpful to me.

Important is to declare the container aliased.

And yes, I rather use an access variable for two reasons.
Performance on one hand as some objects can be very large and hiding the implementation on the other as I plan to use two implementations through a bridge & proxy patterns, one being in in memory XML the other a database.  The bridge pattern handles the options, the proxy (in case for the DB) loading and unloading the data.  The later means that the access variable could point to a complex object with some state information. Currently, I've one package implementing the basic operations on a single subscription for example and another one implementing the collection, as per above code.

> You could also return the Reference_Type itself (slightly safer, as clients 
> would get a compile-time failure). But that would messy (probably you'd want 
> to make it a private type and then derive it from the Reference_Type of the 
> instance). I can show you what I mean on Monday if you can't figure it out 
> yourself (I'll have to code up something to see if it actually works).

As explained, this seems not to suit my current needs, maybe at some point in time I'll see the need/use for this approach.  I'll keep it in mind.

> In any case, the point is that if you are going to eliminate the access 
> types, you really need to eliminate all of them! Leaving some is 
> problematical.

I'm trying to eliminate them as much as possible and where it makes sense, but I won't be pathological about it.

> 
>                                             Randy.

Thank you very much Randy.  You saved my day and motivated me to continue to use Ada for my project.  Moreover, I really believe that the Ada 2012 changes really helps me on my project.

Serge


^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2015-08-09 13:33 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-03 16:08 Design of cross referring types/classes and proper usage of containers Serge Robyns
2015-08-03 16:14 ` Serge Robyns
2015-08-03 20:17   ` Georg Bauhaus
2015-08-03 16:22 ` Dmitry A. Kazakov
2015-08-04 11:43   ` Serge Robyns
2015-08-04 12:13     ` Dmitry A. Kazakov
2015-08-04 19:00       ` Serge Robyns
2015-08-04 19:20         ` Jeffrey R. Carter
2015-08-04 20:27         ` Randy Brukardt
2015-08-04 21:21         ` Simon Wright
2015-08-08 11:25           ` Serge Robyns
2015-08-09  3:11             ` Randy Brukardt
2015-08-09 13:33               ` Serge Robyns
2015-08-05  7:37         ` Dmitry A. Kazakov
2015-08-05 17:51           ` Serge Robyns
2015-08-05 19:21             ` Dmitry A. Kazakov
2015-08-06  7:00               ` Georg Bauhaus

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox