comp.lang.ada
 help / color / mirror / Atom feed
* Smart pointers and delegation
@ 2017-08-01 10:32 Dmitry A. Kazakov
  2017-08-01 15:06 ` Dmitry A. Kazakov
  2017-08-01 23:06 ` Randy Brukardt
  0 siblings, 2 replies; 17+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-01 10:32 UTC (permalink / raw)


I would like to discuss delegation proposal as a replacement for crude, 
inside out Implicit_Dereference aspect.

It goes as follows:

    type I is interface ...
    procedure Foo (X : I);
    function Bar return I;
    procedure Baz (X : in out I);

    [anonymous access argument and result are handled like Foo and Bar]

    type T is new I with ... record
       ...
    end record
       with Delegate[_In|_Out] => Relay;
          -- May appear several times

Here Relay is one of the following:

1. discriminant or component of T (named or anonymous) of access to 
I'Class or an expression of this result;

2. discriminant or component of T (named or anonymous) of access to 
T'Class or an expression of this result;

3. function with the profile:

    function Relay_In (X : T) return [constant] access [all] I'Class;

4. function with the profile:

    function Relay_In (X : T) return I'Class;

5. procedure with the profile:

    procedure Relay_Out (X : [in] out T; Y : [in] out I'Class);

For 1, 2, 3 the compiler overrides Foo, Bar, Baz with the following bodies:

    procedure Foo (X : T) is -- If appears in Delegate[_In]
    begin
       X.Relay_In.Foo;
    end Foo;

    function Bar return T is -- If appears in Delegate[_In]
    begin
       return X.Relay_In.all;
    end Bar;

    procedure Baz (X : in out T) is -- If appears in Delegate and
    begin                           -- not constant
       X.Relay_In.Baz;
    end Baz;

For 4 the compiler overrides Foo and Bar with the bodies like above. Baz 
remains abstract.

    procedure Foo (X : T) is -- If appears in Delegate[_In]
    begin
       X.Relay_In.Foo;
    end Foo;

    function Bar return T is -- If appears in Delegate[_In]
    begin
       return X.Relay_In;
    end Bar;

For 5 the compiler overrides Baz with the body:

    procedure Baz (X : in out T) is -- If Relay_In appears in Delegate_In
    begin                           -- and Relay_Out does in Delegate_Out
       Relay_Out (X, X.Relay_In.Baz);
    end Baz;

Any overriding induced by the Delegate aspect happens only if the 
corresponding operation has not yet been explicitly overridden. 
Conflicting overriding per two Delegate aspects is an error.

-----------------------------------------------------------
Example 1. Smart pointers (handles)

    type File_Interface is interface;
    function Read (File : in out File_Interface)
       return Stream_Element_Array;
    procedure Write (File : in out File_Interface;
                     Data : Stream_Element_Array);


    type File_Handle is new File_Interface with private;

private
    type File_Descriptor is
       new Ada.Finalization.Limited_Controlled
       and File_Interface with
    record
       Use_Count : Natural := 0;
       ...
    end record;
    type File_Descriptor_Ptr is access File_Descriptor'Class;

    type File_Handle is
       new Ada.Finalization.Controlled
       and File_Interface with
    record
       Descriptor : File_Descriptor_Ptr;
    end record with Delegate => Descriptor;

--------------------------------------------------------------
Example 2. Full multiple inheritance

    type A_Interface is limited interface;
    type A is new A_Interface with ...;

    type B is tagged ...;

    type AB is new B and A_Interface with record
       Alter_Ego : aliased A;
    end record with Delegate => A'Access;

--------------------------------------------------------------
Example 3. Parallel pointers hierarchy

    type A_Interface is limited interface;
    type A_Implementation is new A_Interface with ...;
    type A_Reference (Implementation : access A_Implementation'Class) is
       new A_Interface with null record;

    type B_Interface is limited interface;
    type B_Implementation is new A and B_Interface with ...;
    type B_Reference is new A_Reference and B_Interface with
       null record
          with Delegate =>
             B_Imlementation'Class (Implementation.all)'Access;


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

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

* Re: Smart pointers and delegation
  2017-08-01 10:32 Smart pointers and delegation Dmitry A. Kazakov
@ 2017-08-01 15:06 ` Dmitry A. Kazakov
  2017-08-01 23:06 ` Randy Brukardt
  1 sibling, 0 replies; 17+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-01 15:06 UTC (permalink / raw)


On 2017-08-01 12:32, Dmitry A. Kazakov wrote:
> --------------------------------------------------------------
> Example 2. Full multiple inheritance
> 
>     type A_Interface is limited interface;
>     type A is new A_Interface with ...;
> 
>     type B is tagged ...;
> 
>     type AB is new B and A_Interface with record
>        Alter_Ego : aliased A;
>     end record with Delegate => A'Access;
                                   ^^^^^^^^^
                                   Alter_Ego'Access;

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


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

* Re: Smart pointers and delegation
  2017-08-01 10:32 Smart pointers and delegation Dmitry A. Kazakov
  2017-08-01 15:06 ` Dmitry A. Kazakov
@ 2017-08-01 23:06 ` Randy Brukardt
  2017-08-02  6:20   ` Dmitry A. Kazakov
  1 sibling, 1 reply; 17+ messages in thread
From: Randy Brukardt @ 2017-08-01 23:06 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:olplb6$jq0$1@gioia.aioe.org...
>I would like to discuss delegation proposal as a replacement for crude, 
>inside out Implicit_Dereference aspect.

There never are "replacements", as existing Ada code has to work.

And as usual, you didn't explain the problem that you're trying to solve.

Implicit_Dereference was designed so a programmer can get control just 
before and just after the use of a dereference. Indeed, it was a replacement 
for an earlier idea where that was part of a storage pool. The problem with 
the storage pool proposal was determining exactly where a dereference ends. 
The description ended up similar to finalization, so someone suggested tying 
the dereference to a controlled object, and Implicit_Dereference was born.

Implicit_Dereference very much matches the Ada model of "hooks" into 
language-defined operations (much like Adjust and Finalize allow 
user-defined operations to be associated with an assignment, rather than 
replacing it).

The main intended use of this feature was to manage the lifetime of accessed 
entities, such as a persistent store, without requiring copies of the 
contained data (which might be large).

Your proposal doesn't meet this particular need, because there is no way to 
tell when the program is finished with a function result. Thus, you either 
have to copy all of the function results (which is what Ada does), which is 
already determined to be too expensive, or you have to return an unsafe 
access to the object (unsafe because you have no way to find out when the 
access is no longer needed by the program).

It seems to me that you are trying to solve some other problem, rather than 
the low-level one that Implicit_Dereference is trying to solve. Perhaps it 
would be a good idea to articulate the problem before outlining the 
solution??

                                                  Randy.
 



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

* Re: Smart pointers and delegation
  2017-08-01 23:06 ` Randy Brukardt
@ 2017-08-02  6:20   ` Dmitry A. Kazakov
  2017-08-03  3:36     ` Randy Brukardt
  0 siblings, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-02  6:20 UTC (permalink / raw)


On 2017-08-02 01:06, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:olplb6$jq0$1@gioia.aioe.org...
>> I would like to discuss delegation proposal as a replacement for crude,
>> inside out Implicit_Dereference aspect.
> 
> There never are "replacements", as existing Ada code has to work.

It is not replacement in that sense. Replacement here applies to the 
"use case", i.e. creating subtypes. Implicit dereferencing effectively 
makes pointer a "subtype" of the target type.

> And as usual, you didn't explain the problem that you're trying to solve.

The problem is subtyping and automated creation of wrappers to implement 
"trivial" operations. The method is delegation. Examples are presented.

> Implicit_Dereference was designed so a programmer can get control just
> before and just after the use of a dereference.

Certainly not. There is no prologue or epilogue hooks, just one ugly 
access type exposed. Should have been any function or expression 
instead. But it is irrelevant because there is a lot of unwanted and 
damaging stuff that comes with implicit dereferencing making it unusable 
for the use cases in question. Like exposing the target type, which is 
no-no for handle/proxy types. Like making reference objects indefinite etc.

> Implicit_Dereference very much matches the Ada model of "hooks" into
> language-defined operations (much like Adjust and Finalize allow
> user-defined operations to be associated with an assignment, rather than
> replacing it).

? Not even close. Adjust and Finalize are primitive operations, which 
was a horrific design choice, but nevertheless. Implicit dereference is 
not an operation, not even a body.

> The main intended use of this feature was to manage the lifetime of accessed
> entities, such as a persistent store, without requiring copies of the
> contained data (which might be large).

Copies are very essential in many cases, e.g. an external reference to a 
database table row etc. It is up to the programmer to define the semantics.

> Your proposal doesn't meet this particular need, because there is no way to
> tell when the program is finished with a function result.

I don't understand what you mean. The proposal considers exclusively how 
to generate bodies of normal primitive operations. All current rules 
apply to them, no any new rules needed.

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

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

* Re: Smart pointers and delegation
  2017-08-02  6:20   ` Dmitry A. Kazakov
@ 2017-08-03  3:36     ` Randy Brukardt
  2017-08-03  7:40       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 17+ messages in thread
From: Randy Brukardt @ 2017-08-03  3:36 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:olrqum$1t4b$1@gioia.aioe.org...
> On 2017-08-02 01:06, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:olplb6$jq0$1@gioia.aioe.org...
>>> I would like to discuss delegation proposal as a replacement for crude,
>>> inside out Implicit_Dereference aspect.
>>
>> There never are "replacements", as existing Ada code has to work.
>
> It is not replacement in that sense. Replacement here applies to the "use 
> case", i.e. creating subtypes. Implicit dereferencing effectively makes 
> pointer a "subtype" of the target type.

As I noted at the end of my message, your proposal does not replace the "use 
case" for Implicit_Dereference. So this isn't true.

>> And as usual, you didn't explain the problem that you're trying to solve.
>
> The problem is subtyping and automated creation of wrappers to implement 
> "trivial" operations. The method is delegation. Examples are presented.

I think you need to concentrate on describing that problem rather than any 
particular solution to solve it. It doesn't seem like a problem that is 
really solveable in the general case. (Certainly if you want to make some 
sort of proposal; not so much if you are just making talk here.)

...

>> Implicit_Dereference very much matches the Ada model of "hooks" into
>> language-defined operations (much like Adjust and Finalize allow
>> user-defined operations to be associated with an assignment, rather than
>> replacing it).
>
> ? Not even close. Adjust and Finalize are primitive operations, which was 
> a horrific design choice, but nevertheless. Implicit dereference is not an 
> operation, not even a body.

In the intended use, Implicit_Dereference is always combined with a 
controlled type, which provides the actual hooks. As I noted yesterday, the 
original idea was specifically for explicit hooks (as part of the storage 
pool mechanism, similar to Adjust and Finalize), but that got replaced when 
it was pointed out that one could already write the needed support using an 
access discriminant and associated controlled type. That got rid of the need 
to define new mechanisms and deal with the inevitable corner cases. The only 
problem with that was that it was unspeakably ugly, so Implicit_Dereference 
was created to get rid of that without adding any real new semantics.

Any other use of Implicit_Dereference is purely accidental; no other use 
provides anything that can't be written directly in Ada 95.

>> The main intended use of this feature was to manage the lifetime of 
>> accessed
>> entities, such as a persistent store, without requiring copies of the
>> contained data (which might be large).
>
> Copies are very essential in many cases, e.g. an external reference to a 
> database table row etc. It is up to the programmer to define the 
> semantics.

If you want (or don't care about copies) copies, normal primitive functions 
work great. See, for instance, function Element in the various containers 
packages. The access discriminant/controlled type/Implicit_Dereference 
mechanism is intended for those cases where a copy is not usable (either 
because of semantics or because of execution cost).

>> Your proposal doesn't meet this particular need, because there is no way 
>> to
>> tell when the program is finished with a function result.
>
> I don't understand what you mean. The proposal considers exclusively how 
> to generate bodies of normal primitive operations. All current rules apply 
> to them, no any new rules needed.

That's the problem: the Implicit_Dereference mechanism is intended for the 
rare cases where "normal primitive operations" don't work (because they 
imply copies for function results). If "normal primitive operations" work, 
you don't need (and shouldn't use) any special mechanism.

From your description, you're trying to solve an altogether different 
problem. That's fine, of course, but just don't confuse that with the rather 
low-level problem that Implicit_Dereference was actually trying to solve.

                                    Randy.



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

* Re: Smart pointers and delegation
  2017-08-03  3:36     ` Randy Brukardt
@ 2017-08-03  7:40       ` Dmitry A. Kazakov
  2017-08-04 23:03         ` Randy Brukardt
  0 siblings, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-03  7:40 UTC (permalink / raw)


On 2017-08-03 05:36, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:olrqum$1t4b$1@gioia.aioe.org...
>> On 2017-08-02 01:06, Randy Brukardt wrote:
>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>>> news:olplb6$jq0$1@gioia.aioe.org...
>>>> I would like to discuss delegation proposal as a replacement for crude,
>>>> inside out Implicit_Dereference aspect.
>>>
>>> There never are "replacements", as existing Ada code has to work.
>>
>> It is not replacement in that sense. Replacement here applies to the "use
>> case", i.e. creating subtypes. Implicit dereferencing effectively makes
>> pointer a "subtype" of the target type.
> 
> As I noted at the end of my message, your proposal does not replace the "use
> case" for Implicit_Dereference. So this isn't true.
> 
>>> And as usual, you didn't explain the problem that you're trying to solve.
>>
>> The problem is subtyping and automated creation of wrappers to implement
>> "trivial" operations. The method is delegation. Examples are presented.
> 
> I think you need to concentrate on describing that problem rather than any
> particular solution to solve it. It doesn't seem like a problem that is
> really solveable in the general case. (Certainly if you want to make some
> sort of proposal; not so much if you are just making talk here.)

I have no illusions (:-)) So talk would be just fine. Especially if in 
the end the concept catches interest. Delegation is a very powerful 
mechanism which requires very little if any language tampering. It is a 
very nice alternative for generics which does not generate a whole 
second language tier unreadable and unmaintainable.

>>> Implicit_Dereference very much matches the Ada model of "hooks" into
>>> language-defined operations (much like Adjust and Finalize allow
>>> user-defined operations to be associated with an assignment, rather than
>>> replacing it).
>>
>> ? Not even close. Adjust and Finalize are primitive operations, which was
>> a horrific design choice, but nevertheless. Implicit dereference is not an
>> operation, not even a body.
> 
> In the intended use, Implicit_Dereference is always combined with a
> controlled type, which provides the actual hooks.

? These are not hooks on the operation of dereferencing.

[E.g. you cannot make a task-safe dereferencing by taking a lock at the 
beginning and releasing it at the end, i.e. a typical Ref/Unref pair]

[...]

>>> Your proposal doesn't meet this particular need, because there is no way
>>> to tell when the program is finished with a function result.
>>
>> I don't understand what you mean. The proposal considers exclusively how
>> to generate bodies of normal primitive operations. All current rules apply
>> to them, no any new rules needed.
> 
> That's the problem: the Implicit_Dereference mechanism is intended for the
> rare cases where "normal primitive operations" don't work (because they
> imply copies for function results). If "normal primitive operations" work,
> you don't need (and shouldn't use) any special mechanism.

I must and I need it, because in real-life examples (e.g. #1) it is many 
thousands lines of noise code in both package declarations and bodies. 
Which is quite error-prone too.

>  From your description, you're trying to solve an altogether different
> problem. That's fine, of course, but just don't confuse that with the rather
> low-level problem that Implicit_Dereference was actually trying to solve.

Yes it is a wider problem, but one use-case is exactly same. The 
solution is different:

1. Dereference:

    type Target_Interface is interface;
    type Reference (Pointer : access Target_Interface) is null record
       with Implicit_Dereference => Pointer;

2. Delegation:

    type Target_Interface is interface;
    type Reference is new Target_Interface record
       Pointer : access Target_Interface'Class
    end record
       with Delegate => Pointer;

Delegation has no magic whatsoever. It could be done by an ASIS-aware 
preprocessor actually.

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

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

* Re: Smart pointers and delegation
  2017-08-03  7:40       ` Dmitry A. Kazakov
@ 2017-08-04 23:03         ` Randy Brukardt
  2017-08-05  8:33           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 17+ messages in thread
From: Randy Brukardt @ 2017-08-04 23:03 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:oluk0l$a8o$1@gioia.aioe.org...
> On 2017-08-03 05:36, Randy Brukardt wrote:
...
>>> ? Not even close. Adjust and Finalize are primitive operations, which 
>>> was
>>> a horrific design choice, but nevertheless. Implicit dereference is not 
>>> an
>>> operation, not even a body.
>>
>> In the intended use, Implicit_Dereference is always combined with a
>> controlled type, which provides the actual hooks.
>
> ? These are not hooks on the operation of dereferencing.
>
> [E.g. you cannot make a task-safe dereferencing by taking a lock at the 
> beginning and releasing it at the end, i.e. a typical Ref/Unref pair]

Why not? That's precisely the sort of use that is intended. One seizes the 
lock when the dereference object is created (the start of the dereference) 
and the frees it when the dereference object is destroyed (finalized).

> [...]
>> That's the problem: the Implicit_Dereference mechanism is intended for 
>> the
>> rare cases where "normal primitive operations" don't work (because they
>> imply copies for function results). If "normal primitive operations" 
>> work,
>> you don't need (and shouldn't use) any special mechanism.
>
> I must and I need it, because in real-life examples (e.g. #1) it is many 
> thousands lines of noise code in both package declarations and bodies. 
> Which is quite error-prone too.

Sorry, I meant the mechanism as intended is only needed in limited cases. 
You have a very different use-case that has nothing whatsoever to do with 
the need for the Implicit_Dereference mechanism. I didn't intend to say 
anything about the value of that use-case.

Indeed, the proposal you made (as best as I understand it) only used "normal 
primitive operations"; the idea was to automatically construct them in some 
cases. Nothing wrong that I can see with that idea, but it doesn't have 
anything to do with Implicit_Dereference as intended. (You'd still need a 
mechanism like that for uses where copies can't be used, assuming you care 
about safety.)

>>  From your description, you're trying to solve an altogether different
>> problem. That's fine, of course, but just don't confuse that with the 
>> rather
>> low-level problem that Implicit_Dereference was actually trying to solve.
>
> Yes it is a wider problem, but one use-case is exactly same. The solution 
> is different:
>
> 1. Dereference:
>
>    type Target_Interface is interface;
>    type Reference (Pointer : access Target_Interface) is null record
>       with Implicit_Dereference => Pointer;
>
> 2. Delegation:
>
>    type Target_Interface is interface;
>    type Reference is new Target_Interface record
>       Pointer : access Target_Interface'Class
>    end record
>       with Delegate => Pointer;
>
> Delegation has no magic whatsoever. It could be done by an ASIS-aware 
> preprocessor actually.

The problem is that the delegation is unsafe -- it has very different 
semantics. The use of an access discriminant in Implicit_Dereference is what 
gives the limited lifetime to the access type, and that makes it possible to 
use finalization to get control at the end of the life of the dereference.

You can't do that with an ordinary component, which has no limits on the 
lifetime of the dereference. And there is nowhere obvious to hang the "end 
dereference" hook.

That could be fixed with additional new features, I suppose, but the rules 
for access discriminants are such a mess that trying to repeat them in some 
way is not an appealing project (one of the reasons that 
Implicit_Dereference ended up like it did.)

Ergo, (2) is not in any way a replacement for (1). Unless (1) is being used 
without the controlled object and finalization "hook" -- but there is no 
reason whatsoever to do that (you can just use a regular access value in 
that case).

                                                      Randy.


                             Randy.



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

* Re: Smart pointers and delegation
  2017-08-04 23:03         ` Randy Brukardt
@ 2017-08-05  8:33           ` Dmitry A. Kazakov
  2017-08-07 22:39             ` Randy Brukardt
  0 siblings, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-05  8:33 UTC (permalink / raw)


On 2017-08-05 01:03, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:oluk0l$a8o$1@gioia.aioe.org...
>> On 2017-08-03 05:36, Randy Brukardt wrote:
> ...
>>>> ? Not even close. Adjust and Finalize are primitive operations, which
>>>> was
>>>> a horrific design choice, but nevertheless. Implicit dereference is not
>>>> an
>>>> operation, not even a body.
>>>
>>> In the intended use, Implicit_Dereference is always combined with a
>>> controlled type, which provides the actual hooks.
>>
>> ? These are not hooks on the operation of dereferencing.
>>
>> [E.g. you cannot make a task-safe dereferencing by taking a lock at the
>> beginning and releasing it at the end, i.e. a typical Ref/Unref pair]
> 
> Why not? That's precisely the sort of use that is intended. One seizes the
> lock when the dereference object is created (the start of the dereference)
> and the frees it when the dereference object is destroyed (finalized).

What is dereference object? There is a target object X and reference 
object R, both already exist.

Let I want to pass R to an operation F of X. This should lock/unlock on 
the way. I cannot do that without some third type.

>> [...]
>>> That's the problem: the Implicit_Dereference mechanism is intended for the
>>> rare cases where "normal primitive operations" don't work (because they
>>> imply copies for function results). If "normal primitive operations" work,
>>> you don't need (and shouldn't use) any special mechanism.
>>
>> I must and I need it, because in real-life examples (e.g. #1) it is many
>> thousands lines of noise code in both package declarations and bodies.
>> Which is quite error-prone too.
> 
> Sorry, I meant the mechanism as intended is only needed in limited cases.
> You have a very different use-case that has nothing whatsoever to do with
> the need for the Implicit_Dereference mechanism. I didn't intend to say
> anything about the value of that use-case.

Implicit dereferencing semantically does the same. For each visible 
operation of the target type it declares an anonymous operation of the 
reference type that dereferences and then calls to the original operation.

Delegation has these operations named. [and primitive. In this sense it 
is more restricted]

> Indeed, the proposal you made (as best as I understand it) only used "normal
> primitive operations"; the idea was to automatically construct them in some
> cases. Nothing wrong that I can see with that idea, but it doesn't have
> anything to do with Implicit_Dereference as intended. (You'd still need a
> mechanism like that for uses where copies can't be used, assuming you care
> about safety.)
> 
>>>   From your description, you're trying to solve an altogether different
>>> problem. That's fine, of course, but just don't confuse that with the
>>> rather
>>> low-level problem that Implicit_Dereference was actually trying to solve.
>>
>> Yes it is a wider problem, but one use-case is exactly same. The solution
>> is different:
>>
>> 1. Dereference:
>>
>>     type Target_Interface is interface;
>>     type Reference (Pointer : access Target_Interface) is null record
>>        with Implicit_Dereference => Pointer;
>>
>> 2. Delegation:
>>
>>     type Target_Interface is interface;
>>     type Reference is new Target_Interface record
>>        Pointer : access Target_Interface'Class
>>     end record
>>        with Delegate => Pointer;
>>
>> Delegation has no magic whatsoever. It could be done by an ASIS-aware
>> preprocessor actually.
> 
> The problem is that the delegation is unsafe -- it has very different
> semantics. The use of an access discriminant in Implicit_Dereference is what
> gives the limited lifetime to the access type, and that makes it possible to
> use finalization to get control at the end of the life of the dereference.

It could be an access discriminant too. But I used an access component 
to illustrate that it need not to be a discriminant.

The use-case is reference counting smart pointers. I guess you rather 
meant a temporary reference into some container when the reference is 
short-lived and the container element is long-lived.

Smart pointers use the opposite approach. Pointers (the last one) 
outlive the targets. If a container is built then out of smart pointers, 
e.g. it keeps pointers to the elements. Alternatively, it can keep raw 
elements and hold a reference to each. You access elements strictly 
through pointers which need not to be disposed immediately. They can 
live as long as necessary. It can be used in transactional schemes, e.g. 
cloning elements for mutators if the reference count > 1 etc.

> You can't do that with an ordinary component, which has no limits on the
> lifetime of the dereference. And there is nowhere obvious to hang the "end
> dereference" hook.

(I must know what dereference is)

There are cases which do not involve access types. E.g. 
multiple-inheritance for poor:

    type File_Interface is limited interface;
    type File_Type is new File_Interface with ...;

    type Widget is ...;

    type File_Selector_Widget is
       new Widget and File_Interface with
    record
       Selected_File : File_Type;
    end record with Delegate => Selected_File;

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

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

* Re: Smart pointers and delegation
  2017-08-05  8:33           ` Dmitry A. Kazakov
@ 2017-08-07 22:39             ` Randy Brukardt
  2017-08-08  6:27               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 17+ messages in thread
From: Randy Brukardt @ 2017-08-07 22:39 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:om3vsc$jhk$1@gioia.aioe.org...
> On 2017-08-05 01:03, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:oluk0l$a8o$1@gioia.aioe.org...
>>> On 2017-08-03 05:36, Randy Brukardt wrote:
>> ...
>>>>> ? Not even close. Adjust and Finalize are primitive operations, which
>>>>> was
>>>>> a horrific design choice, but nevertheless. Implicit dereference is 
>>>>> not
>>>>> an
>>>>> operation, not even a body.
>>>>
>>>> In the intended use, Implicit_Dereference is always combined with a
>>>> controlled type, which provides the actual hooks.
>>>
>>> ? These are not hooks on the operation of dereferencing.
>>>
>>> [E.g. you cannot make a task-safe dereferencing by taking a lock at the
>>> beginning and releasing it at the end, i.e. a typical Ref/Unref pair]
>>
>> Why not? That's precisely the sort of use that is intended. One seizes 
>> the
>> lock when the dereference object is created (the start of the 
>> dereference)
>> and the frees it when the dereference object is destroyed (finalized).
>
> What is dereference object? There is a target object X and reference 
> object R, both already exist.
>
> Let I want to pass R to an operation F of X. This should lock/unlock on 
> the way. I cannot do that without some third type.

Right. And that's a problem how? Helper types are quite common in ADTs.

>>> [...]
>>>> That's the problem: the Implicit_Dereference mechanism is intended for 
>>>> the
>>>> rare cases where "normal primitive operations" don't work (because they
>>>> imply copies for function results). If "normal primitive operations" 
>>>> work,
>>>> you don't need (and shouldn't use) any special mechanism.
>>>
>>> I must and I need it, because in real-life examples (e.g. #1) it is many
>>> thousands lines of noise code in both package declarations and bodies.
>>> Which is quite error-prone too.
>>
>> Sorry, I meant the mechanism as intended is only needed in limited cases.
>> You have a very different use-case that has nothing whatsoever to do with
>> the need for the Implicit_Dereference mechanism. I didn't intend to say
>> anything about the value of that use-case.
>
> Implicit dereferencing semantically does the same. For each visible 
> operation of the target type it declares an anonymous operation of the 
> reference type that dereferences and then calls to the original operation.

I don't see this at all.

> Delegation has these operations named. [and primitive. In this sense it is 
> more restricted]

Nothing wrong with that per-se, but I fail to see the connection.

...
>> The problem is that the delegation is unsafe -- it has very different
>> semantics. The use of an access discriminant in Implicit_Dereference is 
>> what
>> gives the limited lifetime to the access type, and that makes it possible 
>> to
>> use finalization to get control at the end of the life of the 
>> dereference.
>
> It could be an access discriminant too. But I used an access component to 
> illustrate that it need not to be a discriminant.
>
> The use-case is reference counting smart pointers. I guess you rather 
> meant a temporary reference into some container when the reference is 
> short-lived and the container element is long-lived.

Correct. That was the problematic case.

> Smart pointers use the opposite approach. Pointers (the last one) outlive 
> the targets. If a container is built then out of smart pointers, e.g. it 
> keeps pointers to the elements. Alternatively, it can keep raw elements 
> and hold a reference to each. You access elements strictly through 
> pointers which need not to be disposed immediately. They can live as long 
> as necessary. It can be used in transactional schemes, e.g. cloning 
> elements for mutators if the reference count > 1 etc.

It's not really opposite, though, if you want to limit the lifetime of the 
reference (even if that limit is potentially a long time).

                   Randy.


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

* Re: Smart pointers and delegation
  2017-08-07 22:39             ` Randy Brukardt
@ 2017-08-08  6:27               ` Dmitry A. Kazakov
  2017-08-09  0:27                 ` Randy Brukardt
  0 siblings, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-08  6:27 UTC (permalink / raw)


On 2017-08-08 00:39, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:om3vsc$jhk$1@gioia.aioe.org...

>> Let I want to pass R to an operation F of X. This should lock/unlock on
>> the way. I cannot do that without some third type.
> 
> Right. And that's a problem how? Helper types are quite common in ADTs.

Everything is wrong. Helper type indicates language design problem. Each 
and every type must reflect some entity in the problem space. Helper 
type, as the name suggests, reflects a language problem instead.

>> Implicit dereferencing semantically does the same. For each visible
>> operation of the target type it declares an anonymous operation of the
>> reference type that dereferences and then calls to the original operation.
> 
> I don't see this at all.

You do it with the eyes closed... (:-))

>> Smart pointers use the opposite approach. Pointers (the last one) outlive
>> the targets. If a container is built then out of smart pointers, e.g. it
>> keeps pointers to the elements. Alternatively, it can keep raw elements
>> and hold a reference to each. You access elements strictly through
>> pointers which need not to be disposed immediately. They can live as long
>> as necessary. It can be used in transactional schemes, e.g. cloning
>> elements for mutators if the reference count > 1 etc.
> 
> It's not really opposite, though, if you want to limit the lifetime of the
> reference (even if that limit is potentially a long time).

Why would I want this, if the reference manages the object? The cardinal 
difference is between object-managed references and reference-managed 
objects. The former has a very limited use and would prefer to have all 
of them built-in.

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

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

* Re: Smart pointers and delegation
  2017-08-08  6:27               ` Dmitry A. Kazakov
@ 2017-08-09  0:27                 ` Randy Brukardt
  2017-08-09  7:37                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 17+ messages in thread
From: Randy Brukardt @ 2017-08-09  0:27 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:omblk3$svi$1@gioia.aioe.org...
> On 2017-08-08 00:39, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:om3vsc$jhk$1@gioia.aioe.org...
...
>>> Implicit dereferencing semantically does the same. For each visible
>>> operation of the target type it declares an anonymous operation of the
>>> reference type that dereferences and then calls to the original 
>>> operation.
>>
>> I don't see this at all.
>
> You do it with the eyes closed... (:-))

That's possible. I'm not the best at seeing patterns; I'm much more likely 
to write everything from scratch. Thus I don't find use for interfaces, for 
one example.

...
>> It's not really opposite, though, if you want to limit the lifetime of 
>> the
>> reference (even if that limit is potentially a long time).
>
> Why would I want this, if the reference manages the object? The cardinal 
> difference is between object-managed references and reference-managed 
> objects. The former has a very limited use and would prefer to have all of 
> them built-in.

In that case, you definitely need to know precisely when the reference dies, 
so you can "manage the object". If you have a lifetime leak (such as any 
normal access type does), then you can't do that management safely. The 
pattern of the intended use-case of Implicit_Dereference does exactly this. 
Yes, I agree that it would have been better to have an explicit call-back 
(that was the original idea, after all), but that was a lot more complex in 
language and implementation terms. I don't think the complex version was 
going to fly, and the simple version solves the problem that we needed to 
solve. Sometimes, a "meh" idea that you can actually get implemented is 
better than a brilliant idea that doesn't get any traction and thus never 
actually exists anywhere.

                                          Randy.


                                       Randy.


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

* Re: Smart pointers and delegation
  2017-08-09  0:27                 ` Randy Brukardt
@ 2017-08-09  7:37                   ` Dmitry A. Kazakov
  2017-08-09 22:57                     ` Randy Brukardt
  0 siblings, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-09  7:37 UTC (permalink / raw)


On 2017-08-09 02:27, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:omblk3$svi$1@gioia.aioe.org...

>> Why would I want this, if the reference manages the object? The cardinal
>> difference is between object-managed references and reference-managed
>> objects. The former has a very limited use and would prefer to have all of
>> them built-in.
> 
> In that case, you definitely need to know precisely when the reference dies,
> so you can "manage the object".

Right. That is the advantage of the approach. Reference's life-time is 
better defined than the object's one. E.g. references can be scoped when 
the object cannot. Or, more importantly, when the object must stay 
hidden or is inaccessible like system resource or remote objects.

> If you have a lifetime leak (such as any
> normal access type does), then you can't do that management safely.

It happens when references are components of other objects and/or have 
circular dependencies. Therefore strong and weak references go.

> The pattern of the intended use-case of Implicit_Dereference does exactly this.

It cannot replace smart pointer, because it does not manage the object. 
So the question is whether implicit dereference can be a part of smart 
pointer:

    target <-- smart pointer with implicit dereference

This does not work for multiple reasons either. So the solution could 
only be ugly heavy-weighted:

    target <-- smart pointer
       ||           |
       ||           | operation to produce helper object
       ||           V
    target <-- helper object with implicit dereference

This has no advantages whatsoever. Ergo, implicit dereference has no use 
for smart pointers.

P.S. This is what happens with solutions of "real" problems...

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

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

* Re: Smart pointers and delegation
  2017-08-09  7:37                   ` Dmitry A. Kazakov
@ 2017-08-09 22:57                     ` Randy Brukardt
  2017-08-10  7:56                       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 17+ messages in thread
From: Randy Brukardt @ 2017-08-09 22:57 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:omee2p$145a$1@gioia.aioe.org...
> On 2017-08-09 02:27, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:omblk3$svi$1@gioia.aioe.org...
>
>>> Why would I want this, if the reference manages the object? The cardinal
>>> difference is between object-managed references and reference-managed
>>> objects. The former has a very limited use and would prefer to have all 
>>> of
>>> them built-in.
>>
>> In that case, you definitely need to know precisely when the reference 
>> dies,
>> so you can "manage the object".
>
> Right. That is the advantage of the approach. Reference's life-time is 
> better defined than the object's one. E.g. references can be scoped when 
> the object cannot. Or, more importantly, when the object must stay hidden 
> or is inaccessible like system resource or remote objects.
>
>> If you have a lifetime leak (such as any
>> normal access type does), then you can't do that management safely.
>
> It happens when references are components of other objects and/or have 
> circular dependencies. Therefore strong and weak references go.
>
>> The pattern of the intended use-case of Implicit_Dereference does exactly 
>> this.
>
> It cannot replace smart pointer, because it does not manage the object. So 
> the question is whether implicit dereference can be a part of smart 
> pointer:
>
>    target <-- smart pointer with implicit dereference
>
> This does not work for multiple reasons either.

I find this surprising. It works in the use-cases I've tried. (I haven't 
tried a pure Smart-Pointer, although others have, since I prefer to include 
such things in a larger abstract - like a container).

...
> So the solution could only be ugly heavy-weighted:
>
>    target <-- smart pointer
>       ||           |
>       ||           | operation to produce helper object
>       ||           V
>    target <-- helper object with implicit dereference
>
> This has no advantages whatsoever. Ergo, implicit dereference has no use 
> for smart pointers.

Even if true, the "real problem" however remains. If you can safely and 
efficiently copy the designated object, then you have no need for 
Implicit_Dereference. If you need "return-by-reference", though, you need 
some special mechanism to do that. We tried a variety of approaches, and 
none of them worked out that well (there are 4 alternatives for 
AI05-0142-1). Thus we ended up with Implicit_Dereference.

Perhaps in a brand-new language, it would be possible to make a sensible 
definition of return-by-reference directly, but it doesn't make sense in Ada 
given the existing model and requirements.

                                        Randy.


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

* Re: Smart pointers and delegation
  2017-08-09 22:57                     ` Randy Brukardt
@ 2017-08-10  7:56                       ` Dmitry A. Kazakov
  2017-08-11  0:17                         ` Randy Brukardt
  0 siblings, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-10  7:56 UTC (permalink / raw)


On 2017-08-10 00:57, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:omee2p$145a$1@gioia.aioe.org...

>> It cannot replace smart pointer, because it does not manage the object. So
>> the question is whether implicit dereference can be a part of smart
>> pointer:
>>
>>     target <-- smart pointer with implicit dereference
>>
>> This does not work for multiple reasons either.
> 
> I find this surprising. It works in the use-cases I've tried. (I haven't
> tried a pure Smart-Pointer, although others have, since I prefer to include
> such things in a larger abstract - like a container).

It will have a discriminant, to start with. Smart pointer must be 
aggregation-friendly.

>> So the solution could only be ugly heavy-weighted:
>>
>>     target <-- smart pointer
>>        ||           |
>>        ||           | operation to produce helper object
>>        ||           V
>>     target <-- helper object with implicit dereference
>>
>> This has no advantages whatsoever. Ergo, implicit dereference has no use
>> for smart pointers.
> 
> Even if true, the "real problem" however remains. If you can safely and
> efficiently copy the designated object, then you have no need for
> Implicit_Dereference. If you need "return-by-reference", though, you need
> some special mechanism to do that.

I don't want

    A (I) := X;

taken literally. That is an abstraction inversion. I want it compiled 
into more useful

    Set (A, I, X);

My design of containers is that I effectively put a reference in the 
form of a smart pointer into the container. I don't need return by 
reference because I return a smart pointer, which is definite and 
non-limited. I have no problem with life time because the reference 
holds the object. I less problems with concurrent updates because the 
reference has a count so that the update may deploy a transaction 
scheme. And I tend to hide the referenced object type from public 
interface to make it more safe.

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


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

* Re: Smart pointers and delegation
  2017-08-10  7:56                       ` Dmitry A. Kazakov
@ 2017-08-11  0:17                         ` Randy Brukardt
  2017-08-11  6:43                           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 17+ messages in thread
From: Randy Brukardt @ 2017-08-11  0:17 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:omh3iv$1flt$1@gioia.aioe.org...
> On 2017-08-10 00:57, Randy Brukardt wrote:
...
>> Even if true, the "real problem" however remains. If you can safely and
>> efficiently copy the designated object, then you have no need for
>> Implicit_Dereference. If you need "return-by-reference", though, you need
>> some special mechanism to do that.
>
> I don't want
>
>    A (I) := X;
>
> taken literally. That is an abstraction inversion. I want it compiled into 
> more useful
>
>    Set (A, I, X);

But these are subtly different. The procedure form can only update the 
entire element at once. (Given the potentially large number of 
subcomponents, it would be impractical to implement a procedure for each 
one -- and if you want the compiler to do it, you'd have to be able to 
write - within the language - how that's done, which brings back the 
original question.)

Specifically, if you write:
      A (I).C := Y;
there isn't any translation using Set that would do the right thing. (Using 
an implicit temporary for the entire object would force extra copying, which 
would have performance and tasking implications - it would be outright wrong 
for volatile/atomic objects.)

> My design of containers is that I effectively put a reference in the form 
> of a smart pointer into the container. I don't need return by reference 
> because I return a smart pointer, which is definite and non-limited. I 
> have no problem with life time because the reference holds the object. I 
> less problems with concurrent updates because the reference has a count so 
> that the update may deploy a transaction scheme. And I tend to hide the 
> referenced object type from public interface to make it more safe.

Not sure I see how a "smart pointer" would work in this context. I could 
imagine some sort of handle working if you don't need partial, in-place 
updates. To do that, you have to merge the object interface and the 
container interface; as I noted I sometimes have done designs that way, I 
just don't call the handle a "smart pointer".

                              Randy.


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

* Re: Smart pointers and delegation
  2017-08-11  0:17                         ` Randy Brukardt
@ 2017-08-11  6:43                           ` Dmitry A. Kazakov
  2017-08-11 20:37                             ` Randy Brukardt
  0 siblings, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-11  6:43 UTC (permalink / raw)


On 2017-08-11 02:17, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:omh3iv$1flt$1@gioia.aioe.org...
>> On 2017-08-10 00:57, Randy Brukardt wrote:
> ...
>>> Even if true, the "real problem" however remains. If you can safely and
>>> efficiently copy the designated object, then you have no need for
>>> Implicit_Dereference. If you need "return-by-reference", though, you need
>>> some special mechanism to do that.
>>
>> I don't want
>>
>>     A (I) := X;
>>
>> taken literally. That is an abstraction inversion. I want it compiled into
>> more useful
>>
>>     Set (A, I, X);
> 
> But these are subtly different. The procedure form can only update the
> entire element at once. (Given the potentially large number of
> subcomponents, it would be impractical to implement a procedure for each
> one -- and if you want the compiler to do it, you'd have to be able to
> write - within the language - how that's done, which brings back the
> original question.)
> 
> Specifically, if you write:
>        A (I).C := Y;
> there isn't any translation using Set that would do the right thing. (Using
> an implicit temporary for the entire object would force extra copying, which
> would have performance and tasking implications - it would be outright wrong
> for volatile/atomic objects.)

This is why I am looking for delegation methods in order to route 
operation ".C :=" from element type to the container type:

    Set_C (A, I, Y);

This of course applies to all operations on container elements.

>> My design of containers is that I effectively put a reference in the form
>> of a smart pointer into the container. I don't need return by reference
>> because I return a smart pointer, which is definite and non-limited. I
>> have no problem with life time because the reference holds the object. I
>> less problems with concurrent updates because the reference has a count so
>> that the update may deploy a transaction scheme. And I tend to hide the
>> referenced object type from public interface to make it more safe.
> 
> Not sure I see how a "smart pointer" would work in this context. I could
> imagine some sort of handle working if you don't need partial, in-place
> updates.

Partial updates work because there an explicit operation to get plain 
access type:

    A (I).Ptr.C := Y; -- [*]

But I don't like this sort of things anyway. So usually it is a setter 
defined on the handle:

    A (I).Set_C (Y);

Which is why the handle and the target type implement same interface:

    type Element_Interface is interface;
    procedure Set_C (X : Element_Interface; Y : Integer);

And again I need delegation to automate trivial implementations of the 
interface:

    procedure Set_C (X : Handle; Y : Integer) is
    begin
       X.Ptr.Set_C (Y);
    end Set_C;

which presently I have to write manually.

-----------------------------
* I really do not understand why Implict_Dereference has this ugly form 
instead of simply declaring that type P is a user implementation of 
access-to-T type with user operation to provide access-to-T result. BTW, 
a type can be both access-to-T and access-to-V. Why not? But this is 
another story because smart pointers need not to be access, not visibly.

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


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

* Re: Smart pointers and delegation
  2017-08-11  6:43                           ` Dmitry A. Kazakov
@ 2017-08-11 20:37                             ` Randy Brukardt
  0 siblings, 0 replies; 17+ messages in thread
From: Randy Brukardt @ 2017-08-11 20:37 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:omjjlr$1ia7$1@gioia.aioe.org...
> On 2017-08-11 02:17, Randy Brukardt wrote:
...
>>> My design of containers is that I effectively put a reference in the 
>>> form
>>> of a smart pointer into the container. I don't need return by reference
>>> because I return a smart pointer, which is definite and non-limited. I
>>> have no problem with life time because the reference holds the object. I
>>> less problems with concurrent updates because the reference has a count 
>>> so
>>> that the update may deploy a transaction scheme. And I tend to hide the
>>> referenced object type from public interface to make it more safe.
>>
>> Not sure I see how a "smart pointer" would work in this context. I could
>> imagine some sort of handle working if you don't need partial, in-place
>> updates.
>
> Partial updates work because there an explicit operation to get plain 
> access type:
>
>    A (I).Ptr.C := Y; -- [*]
>
> But I don't like this sort of things anyway.

That's good, because a "plain access type" is dangerous (it has a global 
lifetime if defined in an ADT). Thus it very easily becomes dangling. If all 
you want is something for dereferences, you have to use an anonymous access 
discriminant and a call-back when done, which is the normal usage pattern of 
Implicit_Dereference (of course, you can do that without using 
Implicit_Dereference if you don't mind the extra text as in the above 
assignment).

> So usually it is a setter defined on the handle:
>
>    A (I).Set_C (Y);

That's better, but of course requires a setter for every component. Which 
necessarily merges the container and the element.

...
> -----------------------------
> * I really do not understand why Implict_Dereference has this ugly form 
> instead of simply declaring that type P is a user implementation of 
> access-to-T type with user operation to provide access-to-T result. BTW, a 
> type can be both access-to-T and access-to-V. Why not? But this is another 
> story because smart pointers need not to be access, not visibly.

"Simply"? Not much of anything is "simply" in language terms. 
Implicit_Dereference is relatively simple in language terms because it is 
mainly defined in terms of a text equivalence (thus, few rules have to be 
repeated). I doubt anyone would argue that it is simple in usage terms; the 
theory was that few would care about the details of setting it up, since the 
vast majority would just use it in a container. That's very much like the 
theory behind generics. (And yes, I doubt you would agree with that theory 
in either case.)

No one suggested an idea like the one you gave here, so it certainly was not 
considered. But typically, ambiguity in a type declaration causes problems 
elsewhere. Types are the one thing in Ada that really provide an anchor: 
they can't be overloaded, they always have a single meaning (at a particular 
point in the text, it could change from visibility but nothing else), and so 
on. Changing that might be problematical. But someone would have to do a 
full analysis to be sure, and it is too late for that now.

                             Randy.


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

end of thread, other threads:[~2017-08-11 20:37 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-01 10:32 Smart pointers and delegation Dmitry A. Kazakov
2017-08-01 15:06 ` Dmitry A. Kazakov
2017-08-01 23:06 ` Randy Brukardt
2017-08-02  6:20   ` Dmitry A. Kazakov
2017-08-03  3:36     ` Randy Brukardt
2017-08-03  7:40       ` Dmitry A. Kazakov
2017-08-04 23:03         ` Randy Brukardt
2017-08-05  8:33           ` Dmitry A. Kazakov
2017-08-07 22:39             ` Randy Brukardt
2017-08-08  6:27               ` Dmitry A. Kazakov
2017-08-09  0:27                 ` Randy Brukardt
2017-08-09  7:37                   ` Dmitry A. Kazakov
2017-08-09 22:57                     ` Randy Brukardt
2017-08-10  7:56                       ` Dmitry A. Kazakov
2017-08-11  0:17                         ` Randy Brukardt
2017-08-11  6:43                           ` Dmitry A. Kazakov
2017-08-11 20:37                             ` Randy Brukardt

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