comp.lang.ada
 help / color / mirror / Atom feed
* Getting the index for an element in mutually referencing containers
@ 2017-03-09 13:45 Mart van de Wege
  2017-03-09 15:25 ` Egil H H
       [not found] ` <ly7f3xedp4.fsf@pushface.org>
  0 siblings, 2 replies; 33+ messages in thread
From: Mart van de Wege @ 2017-03-09 13:45 UTC (permalink / raw)



I am missing another thing: I managed to boil down the problem to the
PoC code below. I want to have two objects, each with a container as a
record attribute, referring to each other, and then merely get the index
value of one of the two containers. Yet if I do, I get a Storage_Error
exception.

Code:

with Ada.Containers.Indefinite_Vectors;
with Ada.Containers.Indefinite_Doubly_Linked_Lists;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Test_Container is
   type Abstract_Person is abstract tagged null record;
   package Offspring is new Ada.Containers.Indefinite_Vectors
     (Index_Type => Positive,
      Element_Type => Abstract_Person'Class);
   package Group is new Ada.Containers.Indefinite_Doubly_Linked_Lists
     (Element_Type => Abstract_Person'Class);
   type Person is new Abstract_Person with record
      Children : Offspring.Vector := Offspring.To_Vector(4);
      Parents : Group.List;
   end record;
   Father : Person;
   Child : Person;
begin
   Child.Parents.Prepend(Father);
   Father.Children.Append(Child);
   Put(Integer(Father.Children.Find_Index(Child)));
end Test_Container;

This compiles OK, but on runtime throws an exception:

raised STORAGE_ERROR : stack overflow or erroneous memory access

Now, cyclic dependencies are tricky, so I am sure I am doing something
wrong, but I can't for the life of me see what.

Mart

-- 
"We will need a longer wall when the revolution comes."
    --- AJS, quoting an uncertain source.

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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-09 13:45 Getting the index for an element in mutually referencing containers Mart van de Wege
@ 2017-03-09 15:25 ` Egil H H
  2017-03-09 15:45   ` Mart van de Wege
       [not found] ` <ly7f3xedp4.fsf@pushface.org>
  1 sibling, 1 reply; 33+ messages in thread
From: Egil H H @ 2017-03-09 15:25 UTC (permalink / raw)


On Thursday, March 9, 2017 at 2:50:03 PM UTC+1, Mart van de Wege wrote:
>
>       Children : Offspring.Vector := Offspring.To_Vector(4);
>
>    Put(Integer(Father.Children.Find_Index(Child)));


To_Vector adds empty elements to your list of Children, so Find_Index fails (probably dereferencing null or other erroneouse memory access) when trying to compare them to the Child. Removing the call to To_Vector seems to work as expected...


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-09 15:25 ` Egil H H
@ 2017-03-09 15:45   ` Mart van de Wege
  2017-03-09 16:02     ` Mart van de Wege
  2017-03-09 16:11     ` Egil H H
  0 siblings, 2 replies; 33+ messages in thread
From: Mart van de Wege @ 2017-03-09 15:45 UTC (permalink / raw)


Egil H H <ehh.public@gmail.com> writes:

> On Thursday, March 9, 2017 at 2:50:03 PM UTC+1, Mart van de Wege wrote:
>>
>>       Children : Offspring.Vector := Offspring.To_Vector(4);
>>
>>    Put(Integer(Father.Children.Find_Index(Child)));
>
>
> To_Vector adds empty elements to your list of Children, so Find_Index
> fails (probably dereferencing null or other erroneouse memory access)
> when trying to compare them to the Child. Removing the call to
> To_Vector seems to work as expected...

Aargh. So Find and Find_Index don't just skip empty elements, but die on
them? *That* was not clear from my reading of the spec.

And yes, in actual practice I expect to have sparse Vectors with a few
gaps not holding an Element. So how do I deal with this?

Mart

-- 
"We will need a longer wall when the revolution comes."
    --- AJS, quoting an uncertain source.


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-09 15:45   ` Mart van de Wege
@ 2017-03-09 16:02     ` Mart van de Wege
  2017-03-09 16:11     ` Egil H H
  1 sibling, 0 replies; 33+ messages in thread
From: Mart van de Wege @ 2017-03-09 16:02 UTC (permalink / raw)


Mart van de Wege <mvdwege@gmail.com> writes:

> Egil H H <ehh.public@gmail.com> writes:
>
>> On Thursday, March 9, 2017 at 2:50:03 PM UTC+1, Mart van de Wege wrote:
>>>
>>>       Children : Offspring.Vector := Offspring.To_Vector(4);
>>>
>>>    Put(Integer(Father.Children.Find_Index(Child)));
>>
>>
>> To_Vector adds empty elements to your list of Children, so Find_Index
>> fails (probably dereferencing null or other erroneouse memory access)
>> when trying to compare them to the Child. Removing the call to
>> To_Vector seems to work as expected...
>
> Aargh. So Find and Find_Index don't just skip empty elements, but die on
> them? *That* was not clear from my reading of the spec.
>
> And yes, in actual practice I expect to have sparse Vectors with a few
> gaps not holding an Element. So how do I deal with this?
>
Hmm. Given that Person objects and their derivatives aren't very large,
I could just prefill the Vector with Person objects. As long as I don't
set any of their parameters, they will represent *potential* siblings.

This feels like a hack though.

Mart

-- 
"We will need a longer wall when the revolution comes."
    --- AJS, quoting an uncertain source.


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-09 15:45   ` Mart van de Wege
  2017-03-09 16:02     ` Mart van de Wege
@ 2017-03-09 16:11     ` Egil H H
  1 sibling, 0 replies; 33+ messages in thread
From: Egil H H @ 2017-03-09 16:11 UTC (permalink / raw)


On Thursday, March 9, 2017 at 4:50:04 PM UTC+1, Mart van de Wege wrote:
> 
> Aargh. So Find and Find_Index don't just skip empty elements, but die on
> them? *That* was not clear from my reading of the spec.
> 

Because it's a bug... And it seems to be fixed in (at least) Gnat Pro 17.0

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

* Re: Getting the index for an element in mutually referencing containers
       [not found]         ` <o9vcbp$t0t$1@franka.jacob-sparre.dk>
@ 2017-03-11  6:45           ` Mart van de Wege
  2017-03-11  8:40           ` Simon Wright
  1 sibling, 0 replies; 33+ messages in thread
From: Mart van de Wege @ 2017-03-11  6:45 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> "Mart van de Wege" <mvdwege@gmail.com> wrote in message 
> news:86wpbxneuz.fsf@gaheris.avalon.lan...
>> Simon Wright <simon@pushface.org> writes:
> ...
>>> But, I really think you're going to need to use access types here. A
>>> Person is a unique object, and should only exist once in your data
>>> structures. A Child should hold references to its Parent(s) and vice
>>> versa; if a Child holds *copies* of its Parents, what happens when you
>>> change the Parent's data in one place? how are you going to find all the
>>> copies and change all of them?
>>>
>> That was what I was afraid of. I like the way Ada usually takes care of
>> this for you, but I've been trying to work it out during downtime today
>> at work, and I'm afraid it's indeed time to grab the access types out of
>> the toolbox.
>
> The trick in such cases is to have a global "person" vector, which contains 
> all of the actual Person objects. Then use the cursors into that array in 
> your other data structures. That's gives the needed level of indirection 
> without involving any actual access types (meaning that you let Ada do the 
> storage management, and depending on your container implementation, also 
> reduce/eliminate the danger of dangling access types).
>
Hmm. Given that any roleplaying *campaign*, let alone a single session,
will not have a lot of characters to make that a memory issue, and that
characters are global to the campaign anyway, that makes a good deal of
sense.

Mart

-- 
"We will need a longer wall when the revolution comes."
    --- AJS, quoting an uncertain source.

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

* Re: Getting the index for an element in mutually referencing containers
       [not found]         ` <o9vcbp$t0t$1@franka.jacob-sparre.dk>
  2017-03-11  6:45           ` Mart van de Wege
@ 2017-03-11  8:40           ` Simon Wright
  2017-03-11  8:58             ` Dmitry A. Kazakov
  2017-03-12  1:36             ` Randy Brukardt
  1 sibling, 2 replies; 33+ messages in thread
From: Simon Wright @ 2017-03-11  8:40 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> "Mart van de Wege" <mvdwege@gmail.com> wrote in message 
> news:86wpbxneuz.fsf@gaheris.avalon.lan...
>> Simon Wright <simon@pushface.org> writes:
> ...
>>> But, I really think you're going to need to use access types here. A
>>> Person is a unique object, and should only exist once in your data
>>> structures. A Child should hold references to its Parent(s) and vice
>>> versa; if a Child holds *copies* of its Parents, what happens when
>>> you change the Parent's data in one place? how are you going to find
>>> all the copies and change all of them?
>>>
>> That was what I was afraid of. I like the way Ada usually takes care
>> of this for you, but I've been trying to work it out during downtime
>> today at work, and I'm afraid it's indeed time to grab the access
>> types out of the toolbox.
>
> The trick in such cases is to have a global "person" vector, which
> contains all of the actual Person objects. Then use the cursors into
> that array in your other data structures. That's gives the needed
> level of indirection without involving any actual access types
> (meaning that you let Ada do the storage management, and depending on
> your container implementation, also reduce/eliminate the danger of
> dangling access types).

In the general case, you'd need to cope with deleting (the equivalent
of) Person objects.

And wouldn't even appending a new Person risk invalidating any existing
cursors? AARM A18(5.k) says "Cursors *generally* remain valid as long as
the container exists and the element referenced is not deleted",
emphasis added. AdaCore's Vector implementation would be OK with
inserting elements _after_ the Cursor concerned, since the Cursor is
based on an index into an array. See discussion at AARM A18.2(240) ff.

I quite like the idea of using an indefinite container to hold the
Person objects, but I think I'd use a Map with the key an integer
(Natural?), with the next key held in a private global, incremented as
each new Person is created. The reference to a Person would be the
associated key.

One disadvantage to this design is that Containers hold non-limited
types. Your users run the risk of writing code that gets hold of a copy
of the object and modifies that, rather than modifying the actual
object.

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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-11  8:40           ` Simon Wright
@ 2017-03-11  8:58             ` Dmitry A. Kazakov
  2017-03-11 11:21               ` Simon Wright
  2017-03-12  1:36             ` Randy Brukardt
  1 sibling, 1 reply; 33+ messages in thread
From: Dmitry A. Kazakov @ 2017-03-11  8:58 UTC (permalink / raw)


On 2017-03-11 09:40, Simon Wright wrote:
> "Randy Brukardt" <randy@rrsoftware.com> writes:
>
>> "Mart van de Wege" <mvdwege@gmail.com> wrote in message
>> news:86wpbxneuz.fsf@gaheris.avalon.lan...
>>> Simon Wright <simon@pushface.org> writes:
>> ...
>>>> But, I really think you're going to need to use access types here. A
>>>> Person is a unique object, and should only exist once in your data
>>>> structures. A Child should hold references to its Parent(s) and vice
>>>> versa; if a Child holds *copies* of its Parents, what happens when
>>>> you change the Parent's data in one place? how are you going to find
>>>> all the copies and change all of them?
>>>>
>>> That was what I was afraid of. I like the way Ada usually takes care
>>> of this for you, but I've been trying to work it out during downtime
>>> today at work, and I'm afraid it's indeed time to grab the access
>>> types out of the toolbox.
>>
>> The trick in such cases is to have a global "person" vector, which
>> contains all of the actual Person objects. Then use the cursors into
>> that array in your other data structures. That's gives the needed
>> level of indirection without involving any actual access types
>> (meaning that you let Ada do the storage management, and depending on
>> your container implementation, also reduce/eliminate the danger of
>> dangling access types).
>
> In the general case, you'd need to cope with deleting (the equivalent
> of) Person objects.
>
> And wouldn't even appending a new Person risk invalidating any existing
> cursors? AARM A18(5.k) says "Cursors *generally* remain valid as long as
> the container exists and the element referenced is not deleted",
> emphasis added. AdaCore's Vector implementation would be OK with
> inserting elements _after_ the Cursor concerned, since the Cursor is
> based on an index into an array. See discussion at AARM A18.2(240) ff.
>
> I quite like the idea of using an indefinite container to hold the
> Person objects, but I think I'd use a Map with the key an integer
> (Natural?), with the next key held in a private global, incremented as
> each new Person is created. The reference to a Person would be the
> associated key.

This looks like a clear case for reference counted objects. A handle to 
Person to be put into containers (for search) and into other objects for 
referencing. No problem with limited types. Weak handles are for 
backward referencing and so on.

I often start with a container only to be forced to switch to reference 
counting later, especially when the objects are mutable. There is no 
good containers for mutable types except for built-in arrays.

> One disadvantage to this design is that Containers hold non-limited
> types. Your users run the risk of writing code that gets hold of a copy
> of the object and modifies that, rather than modifying the actual
> object.

A transaction sort of schema can be implemented on top of reference 
counting. E.g. if the count > 1 you clone the object you want to modify.

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


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-11  8:58             ` Dmitry A. Kazakov
@ 2017-03-11 11:21               ` Simon Wright
  2017-03-11 14:18                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 33+ messages in thread
From: Simon Wright @ 2017-03-11 11:21 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> This looks like a clear case for reference counted objects. A handle
> to Person to be put into containers (for search) and into other
> objects for referencing. No problem with limited types. Weak handles
> are for backward referencing and so on.

Does that mean reference-counted _handles_? If you have multiple handles
to a particular Person object, which gets deleted, you'd want all those
handles to be invalidated.


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-11 11:21               ` Simon Wright
@ 2017-03-11 14:18                 ` Dmitry A. Kazakov
  2017-03-11 20:05                   ` Simon Wright
  0 siblings, 1 reply; 33+ messages in thread
From: Dmitry A. Kazakov @ 2017-03-11 14:18 UTC (permalink / raw)


On 2017-03-11 12:21, Simon Wright wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>
>> This looks like a clear case for reference counted objects. A handle
>> to Person to be put into containers (for search) and into other
>> objects for referencing. No problem with limited types. Weak handles
>> are for backward referencing and so on.
>
> Does that mean reference-counted _handles_?

Objects are reference-counted. Handles are not.

> If you have multiple handles
> to a particular Person object, which gets deleted, you'd want all those
> handles to be invalidated.

It is in essence the difference between weak and strong references. If 
you want a reference invalidated when the object vanishes that would be 
a weak reference. In order to access object through weak reference you 
first elevate it to a strong one. You drop the strong reference once you 
used the object.

The semantics of "object deleted" is in question. Usually it is merely 
throwing it out of some list (container) and thus decreasing object's 
reference count. The object stays alive until nobody else uses it = 
nobody holds a strong reference to it.

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


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-11 14:18                 ` Dmitry A. Kazakov
@ 2017-03-11 20:05                   ` Simon Wright
  2017-03-11 20:52                     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 33+ messages in thread
From: Simon Wright @ 2017-03-11 20:05 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> On 2017-03-11 12:21, Simon Wright wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>
>>> This looks like a clear case for reference counted objects. A handle
>>> to Person to be put into containers (for search) and into other
>>> objects for referencing. No problem with limited types. Weak handles
>>> are for backward referencing and so on.
>>
>> Does that mean reference-counted _handles_?
>
> Objects are reference-counted. Handles are not.
>
>> If you have multiple handles
>> to a particular Person object, which gets deleted, you'd want all those
>> handles to be invalidated.
>
> It is in essence the difference between weak and strong references. If
> you want a reference invalidated when the object vanishes that would
> be a weak reference. In order to access object through weak reference
> you first elevate it to a strong one. You drop the strong reference
> once you used the object.
>
> The semantics of "object deleted" is in question. Usually it is merely
> throwing it out of some list (container) and thus decreasing object's
> reference count. The object stays alive until nobody else uses it =
> nobody holds a strong reference to it.

That seems to be a very computer-oriented viewpoint. If your objects
represent real-world objects (or roles, or events - OOA view) then you
wouldn't want them to hang around! If you decide to abort an engagement
and therefore delete the Missile object, whose finalization sends a
self-destruct command to the corresponding missile in flight, you want
it to happen Right Now.


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-11 20:05                   ` Simon Wright
@ 2017-03-11 20:52                     ` Dmitry A. Kazakov
  2017-03-11 21:46                       ` Simon Wright
  0 siblings, 1 reply; 33+ messages in thread
From: Dmitry A. Kazakov @ 2017-03-11 20:52 UTC (permalink / raw)


On 2017-03-11 21:05, Simon Wright wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>
>> On 2017-03-11 12:21, Simon Wright wrote:
>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>>
>>>> This looks like a clear case for reference counted objects. A handle
>>>> to Person to be put into containers (for search) and into other
>>>> objects for referencing. No problem with limited types. Weak handles
>>>> are for backward referencing and so on.
>>>
>>> Does that mean reference-counted _handles_?
>>
>> Objects are reference-counted. Handles are not.
>>
>>> If you have multiple handles
>>> to a particular Person object, which gets deleted, you'd want all those
>>> handles to be invalidated.
>>
>> It is in essence the difference between weak and strong references. If
>> you want a reference invalidated when the object vanishes that would
>> be a weak reference. In order to access object through weak reference
>> you first elevate it to a strong one. You drop the strong reference
>> once you used the object.
>>
>> The semantics of "object deleted" is in question. Usually it is merely
>> throwing it out of some list (container) and thus decreasing object's
>> reference count. The object stays alive until nobody else uses it =
>> nobody holds a strong reference to it.
>
> That seems to be a very computer-oriented viewpoint. If your objects
> represent real-world objects (or roles, or events - OOA view) then you
> wouldn't want them to hang around! If you decide to abort an engagement
> and therefore delete the Missile object, whose finalization sends a
> self-destruct command to the corresponding missile in flight, you want
> it to happen Right Now.

If you have control over it. In the real world, which includes real 
programs, you might have none and there is no such thing as "now" anyway.

Then I would say that rather your idea is computer-oriented. Objects are 
given us in their public operations. Once you cannot apply any to the 
object, or in other semantics, if Object.Exists yields False, there is 
no object. In terms of missiles, when you see a cloud of explosion, the 
work is done. You drop the last your reference and don't care if the 
object transited into another dimension or some object paradise. If you 
don't see it by any programmatic means, then there is none.

P.S. The idea that the world consists of objects is the symbol of faith 
of the Church of Object-Orientation...

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

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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-11 20:52                     ` Dmitry A. Kazakov
@ 2017-03-11 21:46                       ` Simon Wright
  2017-03-11 22:37                         ` Niklas Holsti
  2017-03-12  8:20                         ` Dmitry A. Kazakov
  0 siblings, 2 replies; 33+ messages in thread
From: Simon Wright @ 2017-03-11 21:46 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> On 2017-03-11 21:05, Simon Wright wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>
>>> On 2017-03-11 12:21, Simon Wright wrote:
>>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>> The semantics of "object deleted" is in question. Usually it is merely
>>> throwing it out of some list (container) and thus decreasing object's
>>> reference count. The object stays alive until nobody else uses it =
>>> nobody holds a strong reference to it.
>>
>> That seems to be a very computer-oriented viewpoint. If your objects
>> represent real-world objects (or roles, or events - OOA view) then you
>> wouldn't want them to hang around! If you decide to abort an engagement
>> and therefore delete the Missile object, whose finalization sends a
>> self-destruct command to the corresponding missile in flight, you want
>> it to happen Right Now.
>
> If you have control over it. In the real world, which includes real
> programs, you might have none and there is no such thing as "now"
> anyway.

Of course not. But there is such a thing as avoiding the possibility
of references preventing deletion when deletion needs to happen as soon
as possible.

> Then I would say that rather your idea is computer-oriented. Objects
> are given us in their public operations. Once you cannot apply any to
> the object, or in other semantics, if Object.Exists yields False,
> there is no object. In terms of missiles, when you see a cloud of
> explosion, the work is done. You drop the last your reference and
> don't care if the object transited into another dimension or some
> object paradise. If you don't see it by any programmatic means, then
> there is none.

I (a software Missile object) have been told to delete myself. In my
finalization, I must send a command to my real-world equivalent telling
it to destroy itself. I only need to send it once, because
communications aren't my responsibility (and if comms are down nothing
can be done anyway).


Basically, I (Simon, now) am having trouble thinking of an application
where reference counting would be an appropriate solution.


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-11 21:46                       ` Simon Wright
@ 2017-03-11 22:37                         ` Niklas Holsti
  2017-03-12  8:22                           ` Simon Wright
  2017-03-12  8:20                         ` Dmitry A. Kazakov
  1 sibling, 1 reply; 33+ messages in thread
From: Niklas Holsti @ 2017-03-11 22:37 UTC (permalink / raw)


On 17-03-11 23:46 , Simon Wright wrote:

> Basically, I (Simon, now) am having trouble thinking of an application
> where reference counting would be an appropriate solution.

How about this one: the SW generates messages (telemetry packets) 
reporting various sorts of data and events.

Depending on the kind of the message, the same message may have to be 
distributed within the SW to several destinations: a radio link, a log 
file (mass memory), a message-monitoring service (for possible 
autonomous action), etc.

Each destination has a queue of incoming messages, and the queueing and 
processing time for a given message varies accordingly. Rather than copy 
the (possibly long) message into each destination's queue, the queues 
hold references to a single, shared instance of the message, dynamically 
allocated in a memory pool. These references are counted. When, finally, 
all destinations have processed the message, the message's reference 
count reaches zero, and the message can be deallocated.

This use of reference counting is a typical design in satellite on-board SW.

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
       .      @       .

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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-11  8:40           ` Simon Wright
  2017-03-11  8:58             ` Dmitry A. Kazakov
@ 2017-03-12  1:36             ` Randy Brukardt
  1 sibling, 0 replies; 33+ messages in thread
From: Randy Brukardt @ 2017-03-12  1:36 UTC (permalink / raw)


"Simon Wright" <simon@pushface.org> wrote in message 
news:ly37ekcikw.fsf@pushface.org...
> "Randy Brukardt" <randy@rrsoftware.com> writes:
>
>> "Mart van de Wege" <mvdwege@gmail.com> wrote in message
>> news:86wpbxneuz.fsf@gaheris.avalon.lan...
>>> Simon Wright <simon@pushface.org> writes:
>> ...
>>>> But, I really think you're going to need to use access types here. A
>>>> Person is a unique object, and should only exist once in your data
>>>> structures. A Child should hold references to its Parent(s) and vice
>>>> versa; if a Child holds *copies* of its Parents, what happens when
>>>> you change the Parent's data in one place? how are you going to find
>>>> all the copies and change all of them?
>>>>
>>> That was what I was afraid of. I like the way Ada usually takes care
>>> of this for you, but I've been trying to work it out during downtime
>>> today at work, and I'm afraid it's indeed time to grab the access
>>> types out of the toolbox.
>>
>> The trick in such cases is to have a global "person" vector, which
>> contains all of the actual Person objects. Then use the cursors into
>> that array in your other data structures. That's gives the needed
>> level of indirection without involving any actual access types
>> (meaning that you let Ada do the storage management, and depending on
>> your container implementation, also reduce/eliminate the danger of
>> dangling access types).
>
> In the general case, you'd need to cope with deleting (the equivalent
> of) Person objects.

True, but that's the dangling cursor problem, and you're certainly no worse 
off with a dangling cursor than a dangling access type. (And the container 
implementation might have detection for dangling cursors, that's not likely 
with access types.)

> And wouldn't even appending a new Person risk invalidating any existing
> cursors? AARM A18(5.k) says "Cursors *generally* remain valid as long as
> the container exists and the element referenced is not deleted",
> emphasis added. AdaCore's Vector implementation would be OK with
> inserting elements _after_ the Cursor concerned, since the Cursor is
> based on an index into an array. See discussion at AARM A18.2(240) ff.

With the exception of the Vector container, cursors always stay valid 
through operations on the container. They continue to point at the same 
element no matter what insertions/deletions occur, until of course the 
container itself is destroyed. (Generally, one can't reliably detect cursors 
that point into a destroyed container [since all of the data structures have 
been recycled], but that is a lot less likely problem than a cursor that 
points at a deleted element of a still-existing container.)

The Vector container allows "sliding" of elements, which may (or may not) 
cause a cursor to become invalid. But that can only happen with an 
insertion/deletion *in front* of the cursor -- never with Append. There's a 
bunch of special rules in the RM for that case.

If keeping the cursor stable is a priority, I'd use a list or map container 
rather than a vector. For "Person", a map seems likely (you'd want to be 
able to look them up by name, I'd think).

> I quite like the idea of using an indefinite container to hold the
> Person objects, but I think I'd use a Map with the key an integer
> (Natural?), with the next key held in a private global, incremented as
> each new Person is created. The reference to a Person would be the
> associated key.

That would work but would probably be extra work for no real reason. The 
only real advantage that I can see is that you'd get real dangling reference 
detection with that (without depending upon the container implementation). 
YMMV, of course.

> One disadvantage to this design is that Containers hold non-limited
> types. Your users run the risk of writing code that gets hold of a copy
> of the object and modifies that, rather than modifying the actual
> object.

Right. Not much that can be done about that, unfortunately. Limited types 
seem to defy reusable containerization. I've tried to design such a 
container, but there's always some reason that it won't work without 
introducing access types.

The one thing I've done with Claw programs is to declare the type 
non-limited controlled and override Adjust to raise Program_Error. [Claw 
uses non-limited types, so if you have a window extension that you don't 
want copied, you have to take some action.] But that won't work with the 
containers, as the initial copy would raise Program_Error. If you can live 
with only having default initialization, then you could modify the elements 
in place in such a scenario. But that limits one to definite types.

                               Randy.


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-11 21:46                       ` Simon Wright
  2017-03-11 22:37                         ` Niklas Holsti
@ 2017-03-12  8:20                         ` Dmitry A. Kazakov
  2017-03-12 11:30                           ` Simon Wright
  1 sibling, 1 reply; 33+ messages in thread
From: Dmitry A. Kazakov @ 2017-03-12  8:20 UTC (permalink / raw)


On 2017-03-11 22:46, Simon Wright wrote:

> I (a software Missile object) have been told to delete myself. In my
> finalization, I must send a command to my real-world equivalent telling
> it to destroy itself.

That is OK, but you (as software designer) should also answer the 
question what happens with the missile production log records. Should 
the sad end of the missile erase it from the production log? Tracking 
system?

As a software designer there is only one question. What is the contract 
of Delete? Usually the contract is silent about when the memory is freed 
or Finalization called. If you tried to put finalization into the 
contract you might find very difficult to implement it without breaking 
other contracts. The implementation of Ada container library serves as a 
perfect illustration to this.

> Basically, I (Simon, now) am having trouble thinking of an application
> where reference counting would be an appropriate solution.

As I said, in practice it is all cases when you would have a container 
of mutable elements. It is largely a language problem. But even without 
that, there are cases when you would need multiple references to the 
same element or resource.

E.g. in OS, there is a file object and handles to the file. When you 
tell Delete to a file you do that to the handle. The file is not deleted 
at once. Rather it will be "unnamed" (not instantly ether) and 
physically deleted only when the last handle is closed. And even then it 
could be kept for a while in the recycle bin.

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

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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-11 22:37                         ` Niklas Holsti
@ 2017-03-12  8:22                           ` Simon Wright
  2017-03-12  9:38                             ` G.B.
  2017-03-13 10:29                             ` Alejandro R. Mosteo
  0 siblings, 2 replies; 33+ messages in thread
From: Simon Wright @ 2017-03-12  8:22 UTC (permalink / raw)


Niklas Holsti <niklas.holsti@tidorum.invalid> writes:

> On 17-03-11 23:46 , Simon Wright wrote:
>
>> Basically, I (Simon, now) am having trouble thinking of an
>> application where reference counting would be an appropriate
>> solution.
>
> How about this one: the SW generates messages (telemetry packets)
> reporting various sorts of data and events.
>
[...]
>
> Each destination has a queue of incoming messages, and the queueing
> and processing time for a given message varies accordingly. Rather
> than copy the (possibly long) message into each destination's queue,
> the queues hold references to a single, shared instance of the
> message, dynamically allocated in a memory pool. These references are
> counted. When, finally, all destinations have processed the message,
> the message's reference count reaches zero, and the message can be
> deallocated.
>
> This use of reference counting is a typical design in satellite
> on-board SW.

Thanks for the example!

I still have a feeling that this is an in-computer software technique
which resolves a software problem, rather than a necessary response to
an application-domain problem.


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-12  8:22                           ` Simon Wright
@ 2017-03-12  9:38                             ` G.B.
  2017-03-12 11:21                               ` Simon Wright
  2017-03-13 10:29                             ` Alejandro R. Mosteo
  1 sibling, 1 reply; 33+ messages in thread
From: G.B. @ 2017-03-12  9:38 UTC (permalink / raw)


On 12.03.17 09:22, Simon Wright wrote:
> Niklas Holsti <niklas.holsti@tidorum.invalid> writes:
>
>> On 17-03-11 23:46 , Simon Wright wrote:
>>
>>> Basically, I (Simon, now) am having trouble thinking of an
>>> application where reference counting would be an appropriate
>>> solution.
>>
>> How about this one: the SW generates messages (telemetry packets)
>> reporting various sorts of data and events.
>>
> [...]
>>
>> Each destination has a queue of incoming messages, and the queueing
>> and processing time for a given message varies accordingly. Rather
>> than copy the (possibly long) message into each destination's queue,
>> the queues hold references to a single, shared instance of the
>> message, dynamically allocated in a memory pool. These references are
>> counted. When, finally, all destinations have processed the message,
>> the message's reference count reaches zero, and the message can be
>> deallocated.
>>
>> This use of reference counting is a typical design in satellite
>> on-board SW.
>
> Thanks for the example!

A good one that should have a place in Ada Docs on Stackoverflow,
I think.

> I still have a feeling that this is an in-computer software technique
> which resolves a software problem, rather than a necessary response to
> an application-domain problem.

The radio operators, log inspectors, or message-monitoring staff
might feel overlooked after being changed into a software problem! ;-)


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-12  9:38                             ` G.B.
@ 2017-03-12 11:21                               ` Simon Wright
  0 siblings, 0 replies; 33+ messages in thread
From: Simon Wright @ 2017-03-12 11:21 UTC (permalink / raw)


"G.B." <bauhaus@notmyhomepage.invalid> writes:

> On 12.03.17 09:22, Simon Wright wrote:
>> Niklas Holsti <niklas.holsti@tidorum.invalid> writes:

>>> How about this one: the SW generates messages (telemetry packets)
>>> reporting various sorts of data and events.

>>> This use of reference counting is a typical design in satellite
>>> on-board SW.

>> I still have a feeling that this is an in-computer software technique
>> which resolves a software problem, rather than a necessary response
>> to an application-domain problem.
>
> The radio operators, log inspectors, or message-monitoring staff might
> feel overlooked after being changed into a software problem! ;-)

Yes, but you could solve that by sending a copy of each message to seach
recipient, rather than a reference to a reference-counted
message. Reference counting is a solution to an internal (memory,
possibly time) resource problem.

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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-12  8:20                         ` Dmitry A. Kazakov
@ 2017-03-12 11:30                           ` Simon Wright
  2017-03-12 11:55                             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 33+ messages in thread
From: Simon Wright @ 2017-03-12 11:30 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> On 2017-03-11 22:46, Simon Wright wrote:

>> Basically, I (Simon, now) am having trouble thinking of an application
>> where reference counting would be an appropriate solution.
>
> As I said, in practice it is all cases when you would have a container
> of mutable elements.

I had some trouble understanding your point the first time, and skipped
over it (sorry).

What's the opposite of "mutable"? constant? because, if so, why wouldn't
I use Update_Element? (aside from it being very clumsy; more likely to
use a reference, Person (P).Health := Unwell; )


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-12 11:30                           ` Simon Wright
@ 2017-03-12 11:55                             ` Dmitry A. Kazakov
  2017-03-12 16:44                               ` Simon Wright
  0 siblings, 1 reply; 33+ messages in thread
From: Dmitry A. Kazakov @ 2017-03-12 11:55 UTC (permalink / raw)


On 2017-03-12 12:30, Simon Wright wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>
>> On 2017-03-11 22:46, Simon Wright wrote:
>
>>> Basically, I (Simon, now) am having trouble thinking of an application
>>> where reference counting would be an appropriate solution.
>>
>> As I said, in practice it is all cases when you would have a container
>> of mutable elements.
>
> I had some trouble understanding your point the first time, and skipped
> over it (sorry).
>
> What's the opposite of "mutable"? constant? because, if so, why wouldn't
> I use Update_Element?

Yes, But it is almost never element update. Usually what you want is to 
call some mutable operations on the element. The language does not offer 
user-defined by-reference or copy-out-copy-in methods to element access.

Thus it becomes an access type which opens the whole can of worms. 
Reference counting is merely a method to deal with access types and to 
prevent excessive copying, e.g. when inserting elements.

> (aside from it being very clumsy; more likely to
> use a reference, Person (P).Health := Unwell; )

An access type, you mean. References are only for built-in containers: 
records and arrays.

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


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-12 11:55                             ` Dmitry A. Kazakov
@ 2017-03-12 16:44                               ` Simon Wright
  2017-03-12 17:42                                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 33+ messages in thread
From: Simon Wright @ 2017-03-12 16:44 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> On 2017-03-12 12:30, Simon Wright wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>
>>> On 2017-03-11 22:46, Simon Wright wrote:
>>
>>>> Basically, I (Simon, now) am having trouble thinking of an
>>>> application where reference counting would be an appropriate
>>>> solution.
>>>
>>> As I said, in practice it is all cases when you would have a
>>> container of mutable elements.
>>
>> I had some trouble understanding your point the first time, and
>> skipped over it (sorry).
>>
>> What's the opposite of "mutable"? constant? because, if so, why
>> wouldn't I use Update_Element?
>
> Yes, But it is almost never element update. Usually what you want is
> to call some mutable operations on the element. The language does not
> offer user-defined by-reference or copy-out-copy-in methods to element
> access.

with Ada.Containers.Vectors;
package Mutable_Elements is
   type Element is record
      Numeral : Integer := 0;
   end record;
   procedure Update (E : in out Element);
   package Element_Vectors is new Ada.Containers.Vectors
     (Index_Type => Positive,
      Element_Type => Element);
   Elements : Element_Vectors.Vector;
end Mutable_Elements;

package body Mutable_Elements is
   procedure Update (E : in out Element) is
   begin
      E.Numeral := E.Numeral + 1;
   end Update;
end Mutable_Elements;

with Ada.Text_IO;
with Mutable_Elements;
procedure Mutable_Elements_Test is
   use Mutable_Elements;
begin
   for J in 1 .. 5 loop
      Elements.Append (Element'(Numeral => J));
   end loop;
   
   Elements (4).Numeral := Elements (4).Numeral + 1;
   Ada.Text_IO.Put_Line ("Elements (4).Numeral: "
                           & Elements (4).Numeral'Img);
                           
   Update (Elements (4));
   Ada.Text_IO.Put_Line ("Elements (4).Numeral: "
                           & Elements (4).Numeral'Img);
end Mutable_Elements_Test;

$ ./mutable_elements_test 
Elements (4).Numeral:  5
Elements (4).Numeral:  6


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-12 16:44                               ` Simon Wright
@ 2017-03-12 17:42                                 ` Dmitry A. Kazakov
  2017-03-13 19:55                                   ` Randy Brukardt
  2017-03-13 23:25                                   ` Simon Wright
  0 siblings, 2 replies; 33+ messages in thread
From: Dmitry A. Kazakov @ 2017-03-12 17:42 UTC (permalink / raw)


On 2017-03-12 17:44, Simon Wright wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>
>> On 2017-03-12 12:30, Simon Wright wrote:
>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>>
>>>> On 2017-03-11 22:46, Simon Wright wrote:
>>>
>>>>> Basically, I (Simon, now) am having trouble thinking of an
>>>>> application where reference counting would be an appropriate
>>>>> solution.
>>>>
>>>> As I said, in practice it is all cases when you would have a
>>>> container of mutable elements.
>>>
>>> I had some trouble understanding your point the first time, and
>>> skipped over it (sorry).
>>>
>>> What's the opposite of "mutable"? constant? because, if so, why
>>> wouldn't I use Update_Element?
>>
>> Yes, But it is almost never element update. Usually what you want is
>> to call some mutable operations on the element. The language does not
>> offer user-defined by-reference or copy-out-copy-in methods to element
>> access.
>
> with Ada.Containers.Vectors;
> package Mutable_Elements is
>    type Element is record

[...]

Your example uses access type in Reference_Type which was the point.

Issues to consider are:

1. Two useless Reference_Type type where there should be none, if Ada 
had references.

2. The case of long living multiple references for which Reference_Type 
is no solution.

The case #1 is compiler-managed implicit references or copies. The case 
#2 is user-managed referential helper types. Reference-counted objects 
serve both #1 and #2, being really necessary only for #2.

P.S. It is a pity that Implicit_Dereference type does not have proper 
interface to work with *any* type instead of discriminated records. This 
is design fault when the use case #2 was taken for #1.

P.P.S. Issues with inheritance upon derivation from the container type, 
from the element type, and from both not even mentioned.

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


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-12  8:22                           ` Simon Wright
  2017-03-12  9:38                             ` G.B.
@ 2017-03-13 10:29                             ` Alejandro R. Mosteo
  1 sibling, 0 replies; 33+ messages in thread
From: Alejandro R. Mosteo @ 2017-03-13 10:29 UTC (permalink / raw)


On 12/03/17 09:22, Simon Wright wrote:
> Niklas Holsti <niklas.holsti@tidorum.invalid> writes:
>
>> On 17-03-11 23:46 , Simon Wright wrote:
>>
>>> Basically, I (Simon, now) am having trouble thinking of an
>>> application where reference counting would be an appropriate
>>> solution.
>>
>> How about this one: the SW generates messages (telemetry packets)
>> reporting various sorts of data and events.
>>
> [...]
>>
>> Each destination has a queue of incoming messages, and the queueing
>> and processing time for a given message varies accordingly. Rather
>> than copy the (possibly long) message into each destination's queue,
>> the queues hold references to a single, shared instance of the
>> message, dynamically allocated in a memory pool. These references are
>> counted. When, finally, all destinations have processed the message,
>> the message's reference count reaches zero, and the message can be
>> deallocated.
>>
>> This use of reference counting is a typical design in satellite
>> on-board SW.
>
> Thanks for the example!
>
> I still have a feeling that this is an in-computer software technique
> which resolves a software problem, rather than a necessary response to
> an application-domain problem.

This is how (most? I can only vouch for Java) garbage-collecting 
languages work. Thus is a common way of thinking for many programmers (I 
would say most think first of ref-counted ptrs before weak refs when 
faced with the problem being discussed, but that's just my impression). 
And the source of a kind of memory leak, which is the problem you get in 
exchange for no dangling pointers...

Not surprisingly, C++ has standardized the whole shebang, with both 
semantics being discussed here covered:

http://en.cppreference.com/w/cpp/memory

Alex.

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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-12 17:42                                 ` Dmitry A. Kazakov
@ 2017-03-13 19:55                                   ` Randy Brukardt
  2017-03-13 20:53                                     ` Dmitry A. Kazakov
  2017-03-13 23:25                                   ` Simon Wright
  1 sibling, 1 reply; 33+ messages in thread
From: Randy Brukardt @ 2017-03-13 19:55 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:oa41a4$1ko5$1@gioia.aioe.org...
> On 2017-03-12 17:44, Simon Wright wrote:
...
> P.S. It is a pity that Implicit_Dereference type does not have proper 
> interface to work with *any* type instead of discriminated records. This 
> is design fault when the use case #2 was taken for #1.

It works with any type, since the real target type is the thing designated 
by the discriminant. The discriminant is the key, because it is the only way 
in Ada to get an access type with a controlled lifetime. The discriminated 
type is just a helper, not the end result.

Yes, we could have done that some other way, and indeed we started with a 
separate construct, but the semantics ended up identical to that of an 
access discriminant of a controlled type -- so why build another construct 
(with all of the additional chances of getting it wrong) when an existing 
one will do? Syntax sugar covers up the mess in almost all uses - and that's 
a lot easier to define correctly.

                                                   Randy.



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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-13 19:55                                   ` Randy Brukardt
@ 2017-03-13 20:53                                     ` Dmitry A. Kazakov
  2017-03-14 20:40                                       ` Randy Brukardt
  0 siblings, 1 reply; 33+ messages in thread
From: Dmitry A. Kazakov @ 2017-03-13 20:53 UTC (permalink / raw)


On 2017-03-13 20:55, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:oa41a4$1ko5$1@gioia.aioe.org...
>> On 2017-03-12 17:44, Simon Wright wrote:
> ...
>> P.S. It is a pity that Implicit_Dereference type does not have proper
>> interface to work with *any* type instead of discriminated records. This
>> is design fault when the use case #2 was taken for #1.
>
> It works with any type, since the real target type is the thing designated
> by the discriminant. The discriminant is the key, because it is the only way
> in Ada to get an access type with a controlled lifetime. The discriminated
> type is just a helper, not the end result.

That would be the case #1 with *no* helper type whatsoever:

    type Element ...
    type Index ...
    type Container ...
    function Get (X : Container; I : Index) return Element;
    for Container'Get_Element use Get;

    function Get (X : Container; I : Index) return access Element;
    for Container'Access_Element use Get;

    etc

> Yes, we could have done that some other way,

There is no other way, there is another use case #2, when a reference 
object is required to live longer. That should be *any* type:

    type Reference_Type is private;
private
    function Get (X : Reference_Type) return access Element;
    for Reference_Type'Implicit_Conversion (Element) use Get;

of course it should be inheritance from Element in a better world:

    type Reference_Type is new Element;
private
    function To_Element (X : Reference_Type) return Element;
    for Reference_Type'Upcast_Conversion use To_Element;

by reference:

    type Reference_Type is new access Element;
private
    function To_Element (X : Reference_Type) return access Element;
    for Reference_Type'Upcast_Conversion use To_Element;


> and indeed we started with a
> separate construct, but the semantics ended up identical to that of an
> access discriminant of a controlled type -- so why build another construct
> (with all of the additional chances of getting it wrong) when an existing
> one will do?

Because it gets everything wrong in the major use case #2. You need 
invalidated reference types. A pointer when explicit cannot be 
discriminant and furthermore there might be a pool-specific pointer or 
no pointer at all. And nobody wants to expose pointers under no 
circumstances anyway. When pointers are exposed any shred of safety is gone.

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


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-12 17:42                                 ` Dmitry A. Kazakov
  2017-03-13 19:55                                   ` Randy Brukardt
@ 2017-03-13 23:25                                   ` Simon Wright
  2017-03-14  8:25                                     ` Dmitry A. Kazakov
  1 sibling, 1 reply; 33+ messages in thread
From: Simon Wright @ 2017-03-13 23:25 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> On 2017-03-12 17:44, Simon Wright wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>
>>> On 2017-03-12 12:30, Simon Wright wrote:
>>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>>>
>>>>> On 2017-03-11 22:46, Simon Wright wrote:
>>>>
>>>>>> Basically, I (Simon, now) am having trouble thinking of an
>>>>>> application where reference counting would be an appropriate
>>>>>> solution.
>>>>>
>>>>> As I said, in practice it is all cases when you would have a
>>>>> container of mutable elements.
>>>>
>>>> I had some trouble understanding your point the first time, and
>>>> skipped over it (sorry).
>>>>
>>>> What's the opposite of "mutable"? constant? because, if so, why
>>>> wouldn't I use Update_Element?
>>>
>>> Yes, But it is almost never element update. Usually what you want is
>>> to call some mutable operations on the element. The language does not
>>> offer user-defined by-reference or copy-out-copy-in methods to element
>>> access.
>>
>> with Ada.Containers.Vectors;
>> package Mutable_Elements is
>>    type Element is record
>
> [...]
>
> Your example uses access type in Reference_Type which was the point.

There may be pointers under the hood, just like in assembler there are
registers which denote addresses in store, but there are no pointers
explicitly in the code I wrote; so your assertion (that I couldn't call
operations that change a container element) was wrong.

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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-13 23:25                                   ` Simon Wright
@ 2017-03-14  8:25                                     ` Dmitry A. Kazakov
  0 siblings, 0 replies; 33+ messages in thread
From: Dmitry A. Kazakov @ 2017-03-14  8:25 UTC (permalink / raw)


On 14/03/2017 00:25, Simon Wright wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>
>> On 2017-03-12 17:44, Simon Wright wrote:
>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>>
>>>> On 2017-03-12 12:30, Simon Wright wrote:
>>>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>>>>
>>>>>> On 2017-03-11 22:46, Simon Wright wrote:
>>>>>
>>>>>>> Basically, I (Simon, now) am having trouble thinking of an
>>>>>>> application where reference counting would be an appropriate
>>>>>>> solution.
>>>>>>
>>>>>> As I said, in practice it is all cases when you would have a
>>>>>> container of mutable elements.
>>>>>
>>>>> I had some trouble understanding your point the first time, and
>>>>> skipped over it (sorry).
>>>>>
>>>>> What's the opposite of "mutable"? constant? because, if so, why
>>>>> wouldn't I use Update_Element?
>>>>
>>>> Yes, But it is almost never element update. Usually what you want is
>>>> to call some mutable operations on the element. The language does not
>>>> offer user-defined by-reference or copy-out-copy-in methods to element
>>>> access.
>>>
>>> with Ada.Containers.Vectors;
>>> package Mutable_Elements is
>>>    type Element is record
>>
>> [...]
>>
>> Your example uses access type in Reference_Type which was the point.
>
> There may be pointers under the hood,

Under a straw hat with huge holes meant for ventilation alas exposing 
ugly nasty lack of hair and warts. Pointers are right in the public part 
of Ada.Containers.Vectors.

Even if Reference_Type were an opaque type with no visible access 
discriminant, it would still be a pointer in its semantics with all 
strings attached. Thus if it must be there [*], it must better be a 
smart pointer, e.g. to a reference-counted object.

BTW, reference-counted design gives means to resolve problems with 
at-cursor object deletion and aliased updates in one or another manner.

------------------------
* There should be no helper types needed to access container elements 
"in place".

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


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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-13 20:53                                     ` Dmitry A. Kazakov
@ 2017-03-14 20:40                                       ` Randy Brukardt
  2017-03-15  8:44                                         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 33+ messages in thread
From: Randy Brukardt @ 2017-03-14 20:40 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:oa70rj$12td$1@gioia.aioe.org...
> On 2017-03-13 20:55, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:oa41a4$1ko5$1@gioia.aioe.org...
>>> On 2017-03-12 17:44, Simon Wright wrote:
>> ...
>>> P.S. It is a pity that Implicit_Dereference type does not have proper
>>> interface to work with *any* type instead of discriminated records. This
>>> is design fault when the use case #2 was taken for #1.
>>
>> It works with any type, since the real target type is the thing 
>> designated
>> by the discriminant. The discriminant is the key, because it is the only 
>> way
>> in Ada to get an access type with a controlled lifetime. The 
>> discriminated
>> type is just a helper, not the end result.
>
> That would be the case #1 with *no* helper type whatsoever:
>
>    type Element ...
>    type Index ...
>    type Container ...
>    function Get (X : Container; I : Index) return Element;
>    for Container'Get_Element use Get;
>
>    function Get (X : Container; I : Index) return access Element;
>    for Container'Access_Element use Get;
>
>    etc

The second case here doesn't limit the lifetime of the return access type, 
and provides no notification when the caller is finally finished with the 
accesss value (which is critical). Don't see how that solves anything for 
"case 1".

>> Yes, we could have done that some other way,
>
> There is no other way, there is another use case #2, when a reference 
> object is required to live longer.

We were not trying to solve that problem, it's relatively easy to solve with 
the existing features (as your reference counted library shows). Ada is 
about building blocks, not necessarily polished solutions.

...>> and indeed we started with a
>> separate construct, but the semantics ended up identical to that of an
>> access discriminant of a controlled type -- so why build another 
>> construct
>> (with all of the additional chances of getting it wrong) when an existing
>> one will do?
>
> Because it gets everything wrong in the major use case #2.

Which it was not intended to solve. The whole "strong/weak reference" 
business is not fundemental to solving problems -- if anything, it gets in 
the way. We were only trying to solve the problem of having a reference that 
is still safe (in the sense that the underlying data can be protected from 
destruction while the reference exists). That requires two things: having a 
reference that can't be copied, and having a call-back possibility when the 
reference goes away. The Ada 2012 reference mechanism provides both.

We looked at more complex schemes and they mostly added confusion and 
complexity rather than any benefit. If you want strong and weak references, 
it's easy enough to build them from the parts available.

                                    Randy.



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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-14 20:40                                       ` Randy Brukardt
@ 2017-03-15  8:44                                         ` Dmitry A. Kazakov
  2017-03-15 20:12                                           ` Randy Brukardt
  0 siblings, 1 reply; 33+ messages in thread
From: Dmitry A. Kazakov @ 2017-03-15  8:44 UTC (permalink / raw)


On 2017-03-14 21:40, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:oa70rj$12td$1@gioia.aioe.org...
>> On 2017-03-13 20:55, Randy Brukardt wrote:
>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>>> news:oa41a4$1ko5$1@gioia.aioe.org...
>>>> On 2017-03-12 17:44, Simon Wright wrote:
>>> ...
>>>> P.S. It is a pity that Implicit_Dereference type does not have proper
>>>> interface to work with *any* type instead of discriminated records. This
>>>> is design fault when the use case #2 was taken for #1.
>>>
>>> It works with any type, since the real target type is the thing
>>> designated
>>> by the discriminant. The discriminant is the key, because it is the only
>>> way
>>> in Ada to get an access type with a controlled lifetime. The
>>> discriminated
>>> type is just a helper, not the end result.
>>
>> That would be the case #1 with *no* helper type whatsoever:
>>
>>    type Element ...
>>    type Index ...
>>    type Container ...
>>    function Get (X : Container; I : Index) return Element;
>>    for Container'Get_Element use Get;
>>
>>    function Get (X : Container; I : Index) return access Element;
>>    for Container'Access_Element use Get;
>>
>>    etc
>
> The second case here doesn't limit the lifetime of the return access type,
> and provides no notification when the caller is finally finished with the
> accesss value (which is critical). Don't see how that solves anything for
> "case 1".

It is no problem because the operations are not to be called explicitly. 
They must be private.

I was never a fun of aspects or representation clauses, the proper 
notation should be this:

    function "()" (X : Container; I : Index) return Element;
    procedure "()" (X : in out Container; I : Index; V : Element);

This is for user copy-out / copy-in semantics. And this

    function "()" (X : Container; I : Index)
       return not null access Element;
    procedure "()" (X : in out Container; I : Index; V : not null access 
Element);

For by-reference semantics. The second operation is called to commit 
element transaction. E.g.

    X (I).Member := Foo;

Will be equivalent to

    declare
       Reference : not null access Element := <()> (X, I);
    begin
       Reference.Member := Foo;
       <()> (X, I, Reference);
    exception
       when others =>
          <()> (X, I, Reference);
          raise;
    end;

In particular, the first "()" could take a lock and the second would 
release it.

>>> Yes, we could have done that some other way,
>>
>> There is no other way, there is another use case #2, when a reference
>> object is required to live longer.
>
> We were not trying to solve that problem,

Yes, that is my problem with the design. The use case is #1, the 
solution is #2.

> it's relatively easy to solve with
> the existing features (as your reference counted library shows). Ada is
> about building blocks, not necessarily polished solutions.

It is far from being easy. In practice it leads to a geometric explosion 
of generic instances when a types hierarchy is involved. Believe me, it 
extreme even catastrophic.

The problem is that the smart pointer type must be anonymous (ad-hoc) 
like access T is. Otherwise, you get the problem of parallel type 
hierarchies of the targets and the pointers. And the pointer type must 
have the interface of the target AKA implicit dereference.

> ...>> and indeed we started with a
>>> separate construct, but the semantics ended up identical to that of an
>>> access discriminant of a controlled type -- so why build another
>>> construct
>>> (with all of the additional chances of getting it wrong) when an existing
>>> one will do?
>>
>> Because it gets everything wrong in the major use case #2.
>
> Which it was not intended to solve. The whole "strong/weak reference"
> business is not fundemental to solving problems -- if anything, it gets in
> the way.

Theoretically it is not fundamental, in practice it is. Same as in-out 
parameters. They are not fundamental, any program can theoretically be 
immutable, if you could clone everything including the Universe 
producing program inputs.

> We were only trying to solve the problem of having a reference that
> is still safe (in the sense that the underlying data can be protected from
> destruction while the reference exists). That requires two things: having a
> reference that can't be copied, and having a call-back possibility when the
> reference goes away. The Ada 2012 reference mechanism provides both.

Except that it is not a reference (compiler-managed view of an object), 
it is an object of a different type that plays a role of a reference. 
And this falls right into the use case you didn't want to solve in the 
first place.

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

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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-15  8:44                                         ` Dmitry A. Kazakov
@ 2017-03-15 20:12                                           ` Randy Brukardt
  2017-03-16  2:59                                             ` Paul Rubin
  2017-03-16  9:04                                             ` Dmitry A. Kazakov
  0 siblings, 2 replies; 33+ messages in thread
From: Randy Brukardt @ 2017-03-15 20:12 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:oaausp$ddn$1@gioia.aioe.org...
> On 2017-03-14 21:40, Randy Brukardt wrote:
...
> The problem is that the smart pointer type must be anonymous (ad-hoc) like 
> access T is. Otherwise, you get the problem of parallel type hierarchies 
> of the targets and the pointers. And the pointer type must have the 
> interface of the target AKA implicit dereference.

The problem of parallel type hierarchies is one that MUST be solved if one 
is going to program with hierarchies. It IS fundamental to strong typing, 
unlike most of these other issues. We really need a solution to it (I've 
tried some and intend to try more).

I don't recall ever needing both "strong" or "weak" references to any data 
structure. Most structures only need short-lived references, and the ones 
that need long-lived ones are almost always permanent (only changed between 
runs). Maybe that's because when the only tool you have is an access type, 
every reference looks unchecked and dangerous. :-) But I doubt that many 
problems need or care about the both possibilities.

                          Randy.



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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-15 20:12                                           ` Randy Brukardt
@ 2017-03-16  2:59                                             ` Paul Rubin
  2017-03-16  9:04                                             ` Dmitry A. Kazakov
  1 sibling, 0 replies; 33+ messages in thread
From: Paul Rubin @ 2017-03-16  2:59 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:
> I don't recall ever needing both "strong" or "weak" references to any data 
> structure.

I've only heard of weakrefs in connection with garbage collected
systems, but they are useful there, for dealing with potentially
circular references between long-lived objects.

> Most structures only need short-lived references, and the ones 
> that need long-lived ones are almost always permanent 

That's partly a matter of how the application is organized, which in
turn is influenced by the language features.  In particular, with GC
available, it suddenly becomes less important to carefully manage object
lifetimes and so you get a mixture.  Of course then it's hard to prove
impossibility of OOM crashes, so this may not be a great approach for
critical realtime systems.  But for lots of other tasks it makes
programming easier at the now-cheap cost of a few more computer
resources.

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

* Re: Getting the index for an element in mutually referencing containers
  2017-03-15 20:12                                           ` Randy Brukardt
  2017-03-16  2:59                                             ` Paul Rubin
@ 2017-03-16  9:04                                             ` Dmitry A. Kazakov
  1 sibling, 0 replies; 33+ messages in thread
From: Dmitry A. Kazakov @ 2017-03-16  9:04 UTC (permalink / raw)


On 2017-03-15 21:12, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:oaausp$ddn$1@gioia.aioe.org...
>> On 2017-03-14 21:40, Randy Brukardt wrote:
> ...
>> The problem is that the smart pointer type must be anonymous (ad-hoc) like
>> access T is. Otherwise, you get the problem of parallel type hierarchies
>> of the targets and the pointers. And the pointer type must have the
>> interface of the target AKA implicit dereference.
>
> The problem of parallel type hierarchies is one that MUST be solved if one
> is going to program with hierarchies. It IS fundamental to strong typing,
> unlike most of these other issues. We really need a solution to it (I've
> tried some and intend to try more).

I hope you will find something.

> I don't recall ever needing both "strong" or "weak" references to any data
> structure. Most structures only need short-lived references, and the ones
> that need long-lived ones are almost always permanent (only changed between
> runs). Maybe that's because when the only tool you have is an access type,
> every reference looks unchecked and dangerous. :-) But I doubt that many
> problems need or care about the both possibilities.

1. Say you have a tree. A parent holds references to its children. Each 
child holds a reference to its parent. One of these references must be 
weak or you get a circular lock.

2. Another example. Let you attach a monitoring object to the object 
that emits some events/callbacks. Neither may hold another. The monitor 
can take its leave so the object can. In this case both references are weak.

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


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

end of thread, other threads:[~2017-03-16  9:04 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-09 13:45 Getting the index for an element in mutually referencing containers Mart van de Wege
2017-03-09 15:25 ` Egil H H
2017-03-09 15:45   ` Mart van de Wege
2017-03-09 16:02     ` Mart van de Wege
2017-03-09 16:11     ` Egil H H
     [not found] ` <ly7f3xedp4.fsf@pushface.org>
     [not found]   ` <86k27xpikd.fsf@gaheris.avalon.lan>
     [not found]     ` <lywpbxc9my.fsf@pushface.org>
     [not found]       ` <86wpbxneuz.fsf@gaheris.avalon.lan>
     [not found]         ` <o9vcbp$t0t$1@franka.jacob-sparre.dk>
2017-03-11  6:45           ` Mart van de Wege
2017-03-11  8:40           ` Simon Wright
2017-03-11  8:58             ` Dmitry A. Kazakov
2017-03-11 11:21               ` Simon Wright
2017-03-11 14:18                 ` Dmitry A. Kazakov
2017-03-11 20:05                   ` Simon Wright
2017-03-11 20:52                     ` Dmitry A. Kazakov
2017-03-11 21:46                       ` Simon Wright
2017-03-11 22:37                         ` Niklas Holsti
2017-03-12  8:22                           ` Simon Wright
2017-03-12  9:38                             ` G.B.
2017-03-12 11:21                               ` Simon Wright
2017-03-13 10:29                             ` Alejandro R. Mosteo
2017-03-12  8:20                         ` Dmitry A. Kazakov
2017-03-12 11:30                           ` Simon Wright
2017-03-12 11:55                             ` Dmitry A. Kazakov
2017-03-12 16:44                               ` Simon Wright
2017-03-12 17:42                                 ` Dmitry A. Kazakov
2017-03-13 19:55                                   ` Randy Brukardt
2017-03-13 20:53                                     ` Dmitry A. Kazakov
2017-03-14 20:40                                       ` Randy Brukardt
2017-03-15  8:44                                         ` Dmitry A. Kazakov
2017-03-15 20:12                                           ` Randy Brukardt
2017-03-16  2:59                                             ` Paul Rubin
2017-03-16  9:04                                             ` Dmitry A. Kazakov
2017-03-13 23:25                                   ` Simon Wright
2017-03-14  8:25                                     ` Dmitry A. Kazakov
2017-03-12  1:36             ` Randy Brukardt

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