comp.lang.ada
 help / color / mirror / Atom feed
* Calling inherited primitive operations in Ada
@ 2022-08-31  8:15 Emmanuel Briot
  2022-08-31 17:11 ` DrPi
  2022-08-31 19:13 ` Dmitry A. Kazakov
  0 siblings, 2 replies; 37+ messages in thread
From: Emmanuel Briot @ 2022-08-31  8:15 UTC (permalink / raw)


A small blog post that you might find interesting:

https://deepbluecap.com/calling-inherited-primitive-operations-in-ada/

We are preparing a number of other posts, but right now this is the only one on our web site, so the links are a bit hidden. They will become available on https://deepbluecap.com/blog/ as we publish them.

Emmanuel

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

* Re: Calling inherited primitive operations in Ada
  2022-08-31  8:15 Calling inherited primitive operations in Ada Emmanuel Briot
@ 2022-08-31 17:11 ` DrPi
  2022-08-31 19:13 ` Dmitry A. Kazakov
  1 sibling, 0 replies; 37+ messages in thread
From: DrPi @ 2022-08-31 17:11 UTC (permalink / raw)


Le 31/08/2022 à 10:15, Emmanuel Briot a écrit :
> A small blog post that you might find interesting:
> 
> https://deepbluecap.com/calling-inherited-primitive-operations-in-ada/
> 
> We are preparing a number of other posts, but right now this is the only one on our web site, so the links are a bit hidden. They will become available on https://deepbluecap.com/blog/ as we publish them.
> 
> Emmanuel

That's interesting.

You should compile all excerpts of code you publish. This will avoid 
typos like "Polgyon" ;)

Nicolas

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

* Re: Calling inherited primitive operations in Ada
  2022-08-31  8:15 Calling inherited primitive operations in Ada Emmanuel Briot
  2022-08-31 17:11 ` DrPi
@ 2022-08-31 19:13 ` Dmitry A. Kazakov
  2022-09-01  6:56   ` Emmanuel Briot
  1 sibling, 1 reply; 37+ messages in thread
From: Dmitry A. Kazakov @ 2022-08-31 19:13 UTC (permalink / raw)


On 2022-08-31 10:15, Emmanuel Briot wrote:
> A small blog post that you might find interesting:
> 
> https://deepbluecap.com/calling-inherited-primitive-operations-in-ada/

This same technique is used in generics to work around another language 
design "feature":

    generic
       type Foo is ...;
    package
       subtype Actual_Foo is Foo;

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

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

* Re: Calling inherited primitive operations in Ada
  2022-08-31 19:13 ` Dmitry A. Kazakov
@ 2022-09-01  6:56   ` Emmanuel Briot
       [not found]     ` <67b32db0-c4db-466c-ac13-e597e008c762n@googlegroups.com>
  0 siblings, 1 reply; 37+ messages in thread
From: Emmanuel Briot @ 2022-09-01  6:56 UTC (permalink / raw)


> generic 
> type Foo is ...; 
> package 
> subtype Actual_Foo is Foo; 

To me, this is an orthogonal issue though (which would be worth its own blog post in fact). I can never remember (or perhaps not even understand) the reason for this limitation in Ada, which is a major pain when dealing with generics indeed...
I like the "Actual_" prefix, which I assume is some sort of convention in your code.

Emmanuel

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

* Re: Calling inherited primitive operations in Ada
       [not found]     ` <67b32db0-c4db-466c-ac13-e597e008c762n@googlegroups.com>
@ 2022-09-01 10:02       ` Dmitry A. Kazakov
  2022-09-01 11:59       ` Jeffrey R.Carter
  1 sibling, 0 replies; 37+ messages in thread
From: Dmitry A. Kazakov @ 2022-09-01 10:02 UTC (permalink / raw)


On 2022-09-01 09:57, amo...@unizar.es wrote:
> On Thursday, September 1, 2022 at 8:56:28 AM UTC+2, briot.e...@gmail.com wrote:
>>> generic
>>> type Foo is ...;
>>> package
>>> subtype Actual_Foo is Foo;
>> To me, this is an orthogonal issue though (which would be worth its own blog post in fact). I can never remember (or perhaps not even understand) the reason for this limitation in Ada, which is a major pain when dealing with generics indeed...
>> I like the "Actual_" prefix, which I assume is some sort of convention in your code.
> 
> Is this about how according to some mystifying rules generic formals are[n't] visible from outside the generic?

Right. I do not remember the rules, just the fact that they are quite 
logical. Unfortunately the logic of is not very helpful. (:-))

As for primitive operations the problems are on many levels, from 
lacking introspection to missing inheritance of implementation by 
composition (AKA hooking).

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

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

* Re: Calling inherited primitive operations in Ada
       [not found]     ` <67b32db0-c4db-466c-ac13-e597e008c762n@googlegroups.com>
  2022-09-01 10:02       ` Dmitry A. Kazakov
@ 2022-09-01 11:59       ` Jeffrey R.Carter
  2022-09-01 12:37         ` Dmitry A. Kazakov
  1 sibling, 1 reply; 37+ messages in thread
From: Jeffrey R.Carter @ 2022-09-01 11:59 UTC (permalink / raw)


On 2022-09-01 09:57, amo...@unizar.es wrote:
> 
> Is this about how according to some mystifying rules generic formals are[n't] visible from outside the generic?

This seems like a non-issue to me. Any code that has visibility to a generic 
instance knows the actuals used for that instance. Can anyone provide real 
examples where this is a problem?

-- 
Jeff Carter
"[M]any were collected near them, ... to
enjoy the sight of a dead young lady, nay,
two dead young ladies, for it proved twice
as fine as the first report."
Persuasion
155

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

* Re: Calling inherited primitive operations in Ada
  2022-09-01 11:59       ` Jeffrey R.Carter
@ 2022-09-01 12:37         ` Dmitry A. Kazakov
  2022-09-01 13:37           ` Jeffrey R.Carter
  0 siblings, 1 reply; 37+ messages in thread
From: Dmitry A. Kazakov @ 2022-09-01 12:37 UTC (permalink / raw)


On 2022-09-01 13:59, Jeffrey R.Carter wrote:
> On 2022-09-01 09:57, amo...@unizar.es wrote:
>>
>> Is this about how according to some mystifying rules generic formals 
>> are[n't] visible from outside the generic?
> 
> This seems like a non-issue to me. Any code that has visibility to a 
> generic instance knows the actuals used for that instance.

That would make the code fragile. Should be avoided as much as possible 
as a form of aliasing. Compare:

    procedure A (X : Integer) is
       procedure B (Y : Integer) is
       begin
          X := 1; -- We know we are going to call it with X!
       end B;
    begin
       B (X);
    end A;

> Can anyone 
> provide real examples where this is a problem?

Defaulted formal package actual part:

    generic
       package Foo is new Bar (<>);
    package Baz is ...
       -- What were these actuals in Foo?

This is one of most useful features used to reduce lists of formal 
parameters and simplify instantiations.

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

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

* Re: Calling inherited primitive operations in Ada
  2022-09-01 12:37         ` Dmitry A. Kazakov
@ 2022-09-01 13:37           ` Jeffrey R.Carter
  2022-09-01 14:10             ` Emmanuel Briot
  0 siblings, 1 reply; 37+ messages in thread
From: Jeffrey R.Carter @ 2022-09-01 13:37 UTC (permalink / raw)


On 2022-09-01 14:37, Dmitry A. Kazakov wrote:
> 

Toy problem ignored.

>> Can anyone provide real examples where this is a problem?
 >
> Defaulted formal package actual part:
> 
>     generic
>        package Foo is new Bar (<>);
>     package Baz is ...
>        -- What were these actuals in Foo?

1. The actuals of Foo are visible within Baz.
2. This is not a real example.
3. You have changed the subject from needing to rename a formal type. I presume 
this is because there are no real examples where renaming a formal type in an 
instance is needed.

-- 
Jeff Carter
"[M]any were collected near them, ... to
enjoy the sight of a dead young lady, nay,
two dead young ladies, for it proved twice
as fine as the first report."
Persuasion
155

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

* Re: Calling inherited primitive operations in Ada
  2022-09-01 13:37           ` Jeffrey R.Carter
@ 2022-09-01 14:10             ` Emmanuel Briot
  2022-09-01 15:50               ` amo...@unizar.es
  2022-09-01 16:03               ` Jeffrey R.Carter
  0 siblings, 2 replies; 37+ messages in thread
From: Emmanuel Briot @ 2022-09-01 14:10 UTC (permalink / raw)


I have seen quite a number of cases of needing the subtype like Dmitry was showing. In a small number of cases, those were actual bugs in GNAT, but most of the time the compiler was correct.
Mostly, you start to see the issue when you have generic packages that have formal generic packages.

Here is a quick example and the corresponding compiler error message. In Main, there is no way to see T. Of course, I can use Integer_Signature
directly, but this is an issue.
   - if I rename Integer_Signature then I have to change a lot of places in my code (The aliasing that Dmitry was talking about)

with Signature;
generic
   with package Sign is new Signature (<>);
package Algo is
   procedure Compute (V : Sign.T) is null;
end Algo;

with Algo;
with Signature;
package Lib is
   package Integer_Signature is new Signature (Integer);
   package Integer_Algo is new Algo (Integer_Signature);
end Lib;


with Lib;
procedure Main is
   V : Lib.Integer_Algo.Sign.T;
   --   main.adb:3:24: "Sign" is not a visible entity of "Integer_Algo"
begin
   null;
end Main;

generic
   type T is private;
package Signature is
end Signature;

There are more interesting examples, somehow this one doesn't seem that bad. So here is another one:

    generic
       type T is private;
    package Gen is
    end Gen;

    with Gen;
    generic
       type T is private;
       with package Must_Match is new Gen (T);
       with package Need_Not_Match is new Gen (<>);
    package Gen2 is
       V1 : Must_Match.T;         --  "T" is not a visible entity of "Must_Match"
       V2 : Need_Not_Match.T;  -- instance of same package, but this time T is visible
    end Gen2;

    with Gen, Gen2;
    procedure P2 is
       package G is new Gen (Integer);
       package G2 is new Gen2 (Integer, G, G);
    begin
       null;
    end P2;




I dug out the explanation that Tucker Taft once sent to the Ada-Comment mailing list (2019-11-14):

<<<
10/2
{AI95-00317-01} The visible part of a formal package includes the first list of basic_declarative_items of the package_specification. In addition, for each actual parameter that is not required to match, a copy of the declaration of the corresponding formal parameter of the template is included in the visible part of the formal package. If the copied declaration is for a formal type, copies of the implicit declarations of the primitive subprograms of the formal type are also included in the visible part of the formal package.
10.a/2
Ramification: {AI95-00317-01} If the formal_package_actual_part is (<>), then the declarations that occur immediately within the generic_formal_part of the template for the formal package are visible outside the formal package, and can be denoted by expanded names outside the formal package.If only some of the actual parameters are given by <>, then the declaration corresponding to those parameters (but not the others) are made visible.
10.b/3
Reason: {AI05-0005-1} We always want either the actuals or the formals of an instance to be nameable from outside, but never both. If both were nameable, one would get some funny anomalies since they denote the same entity, but, in the case of types at least, they might have different and inconsistent sets of primitive operators due to predefined operator “reemergence.” Formal derived types exacerbate the difference. We want the implicit declarations of the generic_formal_part as well as the explicit declarations, so we get operations on the formal types.  
>>>

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

* Re: Calling inherited primitive operations in Ada
  2022-09-01 14:10             ` Emmanuel Briot
@ 2022-09-01 15:50               ` amo...@unizar.es
  2022-09-01 16:03               ` Jeffrey R.Carter
  1 sibling, 0 replies; 37+ messages in thread
From: amo...@unizar.es @ 2022-09-01 15:50 UTC (permalink / raw)


On Thursday, September 1, 2022 at 4:11:54 PM UTC+2, briot.e...@gmail.com wrote:
> I have seen quite a number of cases of needing the subtype like Dmitry was showing. In a small number of cases, those were actual bugs in GNAT, but most of the time the compiler was correct. 
> Mostly, you start to see the issue when you have generic packages that have formal generic packages. 

This matches exactly my experience. I don't have enough grasp of the details to come up with a realistic short example, but I did hit this issue pretty often in two libs were I used signature packages quite extensively:

https://github.com/mosteo/rxada
https://github.com/mosteo/iterators

Initially I was always under the impression I was hitting GNAT bugs but then it turned out there were rules about it. A couple example places (you can see the renamings at the top. I was adding them "on demand" so to say):

https://github.com/mosteo/iterators/blob/master/src/iterators-traits-containers.ads
https://github.com/mosteo/rxada/blob/master/src/priv/rx-impl-transformers.ads
 
Thanks Emmanuel for the examples and digging out Tucker explanation.

-Alex.

> There are more interesting examples, somehow this one doesn't seem that bad. So here is another one: 
> 
> generic 
> type T is private; 
> package Gen is 
> end Gen; 
> 
> with Gen; 
> generic 
> type T is private; 
> with package Must_Match is new Gen (T); 
> with package Need_Not_Match is new Gen (<>); 
> package Gen2 is 
> V1 : Must_Match.T; -- "T" is not a visible entity of "Must_Match" 
> V2 : Need_Not_Match.T; -- instance of same package, but this time T is visible 
> end Gen2; 
> 
> with Gen, Gen2; 
> procedure P2 is 
> package G is new Gen (Integer); 
> package G2 is new Gen2 (Integer, G, G); 
> begin 
> null; 
> end P2; 
> 
> 
> 
> 
> I dug out the explanation that Tucker Taft once sent to the Ada-Comment mailing list (2019-11-14): 
> 
> <<< 
> 10/2 
> {AI95-00317-01} The visible part of a formal package includes the first list of basic_declarative_items of the package_specification. In addition, for each actual parameter that is not required to match, a copy of the declaration of the corresponding formal parameter of the template is included in the visible part of the formal package. If the copied declaration is for a formal type, copies of the implicit declarations of the primitive subprograms of the formal type are also included in the visible part of the formal package. 
> 10.a/2 
> Ramification: {AI95-00317-01} If the formal_package_actual_part is (<>), then the declarations that occur immediately within the generic_formal_part of the template for the formal package are visible outside the formal package, and can be denoted by expanded names outside the formal package.If only some of the actual parameters are given by <>, then the declaration corresponding to those parameters (but not the others) are made visible. 
> 10.b/3 
> Reason: {AI05-0005-1} We always want either the actuals or the formals of an instance to be nameable from outside, but never both. If both were nameable, one would get some funny anomalies since they denote the same entity, but, in the case of types at least, they might have different and inconsistent sets of primitive operators due to predefined operator “reemergence.” Formal derived types exacerbate the difference. We want the implicit declarations of the generic_formal_part as well as the explicit declarations, so we get operations on the formal types. 
> >>>

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

* Re: Calling inherited primitive operations in Ada
  2022-09-01 14:10             ` Emmanuel Briot
  2022-09-01 15:50               ` amo...@unizar.es
@ 2022-09-01 16:03               ` Jeffrey R.Carter
  2022-09-01 16:07                 ` Emmanuel Briot
  1 sibling, 1 reply; 37+ messages in thread
From: Jeffrey R.Carter @ 2022-09-01 16:03 UTC (permalink / raw)


On 2022-09-01 16:10, Emmanuel Briot wrote:
> I have seen quite a number of cases of needing the subtype like Dmitry was showing. In a small number of cases, those were actual bugs in GNAT, but most of the time the compiler was correct.
> Mostly, you start to see the issue when you have generic packages that have formal generic packages.

None of these deal with the example I responded to

generic
    type T is ...
package P is
    subtype Actual_T is T;

> Reason: {AI05-0005-1} We always want either the actuals or the formals of an instance to be nameable from outside, but never both.
This is true in all these examples. I have used Ada since 1984, and this has 
never been a problem for me (as initially presented, this would have existed in 
Ada 83). Of course, I generally avoid generic formal pkgs. They seem to me to be 
a work around for poor design, and I prefer to correct the design.

-- 
Jeff Carter
"[M]any were collected near them, ... to
enjoy the sight of a dead young lady, nay,
two dead young ladies, for it proved twice
as fine as the first report."
Persuasion
155

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

* Re: Calling inherited primitive operations in Ada
  2022-09-01 16:03               ` Jeffrey R.Carter
@ 2022-09-01 16:07                 ` Emmanuel Briot
  2022-09-01 16:17                   ` Jeffrey R.Carter
  0 siblings, 1 reply; 37+ messages in thread
From: Emmanuel Briot @ 2022-09-01 16:07 UTC (permalink / raw)


On Thursday, September 1, 2022 at 6:03:22 PM UTC+2, Jeffrey R.Carter wrote:
> This is true in all these examples. I have used Ada since 1984, and this has 
> never been a problem for me (as initially presented, this would have existed in 

So basically saying that you do not use generics (or only very basic versions) and you have never seen
the bug that relates to complex generics. Not very useful input ?
For sure, that's already a number of persons who have said they have seen this bug a number of times.
I have of course only been using Ada for 25 years, but that sure was enough to see that issue...

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

* Re: Calling inherited primitive operations in Ada
  2022-09-01 16:07                 ` Emmanuel Briot
@ 2022-09-01 16:17                   ` Jeffrey R.Carter
  2022-09-01 18:54                     ` Emmanuel Briot
  0 siblings, 1 reply; 37+ messages in thread
From: Jeffrey R.Carter @ 2022-09-01 16:17 UTC (permalink / raw)


On 2022-09-01 18:07, Emmanuel Briot wrote:
> 
> So basically saying that you do not use generics (or only very basic versions) and you have never seen
> the bug that relates to complex generics. Not very useful input ?

I have not said this. I have worked on very large problems and on generics 
appropriate to such problems. Of course, KISS is an important S/W-eng principle.

-- 
Jeff Carter
"[M]any were collected near them, ... to
enjoy the sight of a dead young lady, nay,
two dead young ladies, for it proved twice
as fine as the first report."
Persuasion
155

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

* Re: Calling inherited primitive operations in Ada
  2022-09-01 16:17                   ` Jeffrey R.Carter
@ 2022-09-01 18:54                     ` Emmanuel Briot
  2022-09-01 21:33                       ` Jeffrey R.Carter
  0 siblings, 1 reply; 37+ messages in thread
From: Emmanuel Briot @ 2022-09-01 18:54 UTC (permalink / raw)


I think I have a more interesting example. This one is extracted from my attempted traits containers, for which I had published a blog post at AdaCore. My enhanced fork of the library is at 
 https://github.com/briot/ada-traits-containers
if someone wants to experiment with non-trivial generics code (and containers are of course a case where generics fully make sense).

Here is the example:

generic
   type Element_Type is private;
   type Stored_Type is private;
package Elements is
end Elements;

with Elements;
generic
   type Element_Type is private;
package Definite_Elements is
   package Traits is new Elements (Element_Type, Stored_Type => Element_Type);
end Definite_Elements;

with Definite_Elements;
generic
   type Key_Type is private;
package Maps is
   package Keys is new Definite_Elements (Key_Type);
   function "=" (L, R : Keys.Traits.Stored_Type) return Boolean   --   "Stored_Type" is not a visible entity of "Traits"
      is (False);
end Maps;


This is not case where the actual is visible unless I happen to know how Definite_Element is implemented and that it will use Element_Type for Stored_Type (and this is not a knowledge I wish client packages to have, the whole point of Element and Definite_Element is to basically hide how elements can be stored in a container, and whether we need memory allocation for instance).

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

* Re: Calling inherited primitive operations in Ada
  2022-09-01 18:54                     ` Emmanuel Briot
@ 2022-09-01 21:33                       ` Jeffrey R.Carter
  2022-09-02  6:11                         ` Emmanuel Briot
  2022-09-02  8:35                         ` amo...@unizar.es
  0 siblings, 2 replies; 37+ messages in thread
From: Jeffrey R.Carter @ 2022-09-01 21:33 UTC (permalink / raw)


On 2022-09-01 20:54, Emmanuel Briot wrote:
> 
> generic
>     type Element_Type is private;
>     type Stored_Type is private;
> package Elements is
> end Elements;
> 
> with Elements;
> generic
>     type Element_Type is private;
> package Definite_Elements is
>     package Traits is new Elements (Element_Type, Stored_Type => Element_Type);
> end Definite_Elements;
> 
> with Definite_Elements;
> generic
>     type Key_Type is private;
> package Maps is
>     package Keys is new Definite_Elements (Key_Type);
>     function "=" (L, R : Keys.Traits.Stored_Type) return Boolean   --   "Stored_Type" is not a visible entity of "Traits"
>        is (False);
> end Maps;

As presented, this seems very over complicated. Elements and Definite_Elements 
add no value, and this is just a complex way of writing

generic
    type Key is private;
package Maps is
    function "=" (L : in Key; R : in Key) return Boolean is (False);
end Maps;

One hopes that the actual library makes better use of these pkgs than this small 
example.

> This is not case where the actual is visible unless I happen to know how Definite_Element is implemented and that it will use Element_Type for Stored_Type (and this is not a knowledge I wish client packages to have, the whole point of Element and Definite_Element is to basically hide how elements can be stored in a container, and whether we need memory allocation for instance).

Ada has excellent features for hiding, but these are not among them. Assuming 
that pkg Keys serves some actual role in the spec of Maps, then someone wanting 
to use pkg Maps will need to understand that role, which involves understanding 
Definite_Elements, which involves understanding pkg Traits, which involves 
understanding Elements. Rather than hiding anything, you are effectively 
requiring your users to look at these things, even if you could use the notation 
in question.

-- 
Jeff Carter
"[M]any were collected near them, ... to
enjoy the sight of a dead young lady, nay,
two dead young ladies, for it proved twice
as fine as the first report."
Persuasion
155

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

* Re: Calling inherited primitive operations in Ada
  2022-09-01 21:33                       ` Jeffrey R.Carter
@ 2022-09-02  6:11                         ` Emmanuel Briot
  2022-09-02 10:55                           ` Jeffrey R.Carter
  2022-09-03  0:07                           ` Randy Brukardt
  2022-09-02  8:35                         ` amo...@unizar.es
  1 sibling, 2 replies; 37+ messages in thread
From: Emmanuel Briot @ 2022-09-02  6:11 UTC (permalink / raw)


> As presented, this seems very over complicated. Elements and Definite_Elements 
> add no value, and this is just a complex way of writing 

I did point you to the full repository if you prefer an extensive, real-life code sample. This was just an extract showing the gist of the issue.

> One hopes that the actual library makes better use of these pkgs than this small 
> example.

One can check the full code and extensive documentation on the design in the github repository.
This is called code reuse, was invented quite a while ago.
These packages are mostly implementation details. They are used to build high-level packages similar to the Ada containers, except with much better code reuse, more efficient, and SPARK-provable.

> Ada has excellent features for hiding, but these are not among them. Assuming 

And that's exactly our point in this discussion. Ada on the whole is very good (we would not be using it otherwise), but it does have a number of limitations which are sometimes a pain, this being one of them. Not acknowledging the limitations when they exist is naive, all languages have them.

> that pkg Keys serves some actual role in the spec of Maps, then someone wanting 
> to use pkg Maps will need to understand that role, which involves understanding 
> Definite_Elements, which involves understanding pkg Traits, which involves 
> understanding Elements. 

which involves understanding Ada, which involves understanding the compiler, which involves understanding the kernel sources, ...
How many times have you checked the whole sources of the GNAT runtime to understand how they implemented the Ada containers ?

Emmanuel

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

* Re: Calling inherited primitive operations in Ada
  2022-09-01 21:33                       ` Jeffrey R.Carter
  2022-09-02  6:11                         ` Emmanuel Briot
@ 2022-09-02  8:35                         ` amo...@unizar.es
  2022-09-02  8:48                           ` Dmitry A. Kazakov
                                             ` (2 more replies)
  1 sibling, 3 replies; 37+ messages in thread
From: amo...@unizar.es @ 2022-09-02  8:35 UTC (permalink / raw)


On Thursday, September 1, 2022 at 11:33:47 PM UTC+2, Jeffrey R.Carter wrote:
> On 2022-09-01 20:54, Emmanuel Briot wrote: 

> As presented, this seems very over complicated. Elements and Definite_Elements 
> add no value, and this is just a complex way of writing 

Going in a tangent, and I guess you know perfectly well, but this is caused by the painful duplication of code that Ada pushes you to by not having a native way to abstract storage of definite vs indefinite types. So the provider of a generic library very soon faces this conundrum about duplicating most interfaces, if not implementations, or resort to non-trivial generics, or accept an unnecessary penalty for definite types, or push to the client the definite storage matter. There's simply no satisfying solution here [that I know of]. The duplication of every standard container to have both [in]definite variants is a strong indictment. 

I can understand the desire to have full control of allocation and object sizes, but that there's not a language way to work around this duplication, with appropriate restrictions to go with it, is... bothersome. Not making a dig at the ARG, which I understand is overstretched as it is. 

There was a proposal circulating some time ago that seemed promising, that I can't quickly find. Something like

type Blah is record
    Dont_care_if_in_heap: new Whatever_Definiteness; -- Would apply to indefinite types or formals
end record;

I don't think it made into https://github.com/AdaCore/ada-spark-rfcs/ or https://github.com/Ada-Rapporteur-Group/User-Community-Input/issues or I can't find it.

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

* Re: Calling inherited primitive operations in Ada
  2022-09-02  8:35                         ` amo...@unizar.es
@ 2022-09-02  8:48                           ` Dmitry A. Kazakov
       [not found]                             ` <9484a755-f55d-407e-a40b-92421b0bcafbn@googlegroups.com>
  2022-09-02 10:41                           ` Jeffrey R.Carter
  2022-09-03  0:01                           ` Randy Brukardt
  2 siblings, 1 reply; 37+ messages in thread
From: Dmitry A. Kazakov @ 2022-09-02  8:48 UTC (permalink / raw)


On 2022-09-02 10:35, amo...@unizar.es wrote:
> On Thursday, September 1, 2022 at 11:33:47 PM UTC+2, Jeffrey R.Carter wrote:
>> On 2022-09-01 20:54, Emmanuel Briot wrote:
> 
>> As presented, this seems very over complicated. Elements and Definite_Elements
>> add no value, and this is just a complex way of writing
> 
> Going in a tangent, and I guess you know perfectly well, but this is caused by the painful duplication of code that Ada pushes you to by not having a native way to abstract storage of definite vs indefinite types. So the provider of a generic library very soon faces this conundrum about duplicating most interfaces, if not implementations, or resort to non-trivial generics, or accept an unnecessary penalty for definite types, or push to the client the definite storage matter. There's simply no satisfying solution here [that I know of]. The duplication of every standard container to have both [in]definite variants is a strong indictment.
> 
> I can understand the desire to have full control of allocation and object sizes, but that there's not a language way to work around this duplication, with appropriate restrictions to go with it, is... bothersome. Not making a dig at the ARG, which I understand is overstretched as it is.

Containers should be implementable without generics. Just saying.

> There was a proposal circulating some time ago that seemed promising, that I can't quickly find. Something like
> 
> type Blah is record
>      Dont_care_if_in_heap: new Whatever_Definiteness; -- Would apply to indefinite types or formals
> end record;

I would prefer constraint propagation/management support + tuples instead:

    type Blah (Parameters : Whatever_Definiteness'Constraints) is
       Sill_Care : Whatever_Definiteness (Parameters);
    end record;

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

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

* Re: Calling inherited primitive operations in Ada
       [not found]                             ` <9484a755-f55d-407e-a40b-92421b0bcafbn@googlegroups.com>
@ 2022-09-02  9:55                               ` Dmitry A. Kazakov
  0 siblings, 0 replies; 37+ messages in thread
From: Dmitry A. Kazakov @ 2022-09-02  9:55 UTC (permalink / raw)


On 2022-09-02 11:20, amo...@unizar.es wrote:
> On Friday, September 2, 2022 at 10:48:57 AM UTC+2, Dmitry A. Kazakov wrote:
> 
>> Containers should be implementable without generics. Just saying.
> 
> Are you now referring to current Ada or to hypothetical features?

Hypothetical like all types having classes and supertypes. E.g. when you 
instantiate generic with a type you semantically place the type in the 
implicit class of formal types of the generic. You cannot do that now 
without generics. Furthermore, there is no way to describe relationships 
between types like array index and array, like range and discrete type 
of its elements etc.

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

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

* Re: Calling inherited primitive operations in Ada
  2022-09-02  8:35                         ` amo...@unizar.es
  2022-09-02  8:48                           ` Dmitry A. Kazakov
@ 2022-09-02 10:41                           ` Jeffrey R.Carter
  2022-09-02 11:04                             ` Dmitry A. Kazakov
  2022-09-03  0:01                           ` Randy Brukardt
  2 siblings, 1 reply; 37+ messages in thread
From: Jeffrey R.Carter @ 2022-09-02 10:41 UTC (permalink / raw)


On 2022-09-02 10:35, amo...@unizar.es wrote:
> 
> Going in a tangent, and I guess you know perfectly well, but this is caused by the painful duplication of code that Ada pushes you to by not having a native way to abstract storage of definite vs indefinite types. So the provider of a generic library very soon faces this conundrum about duplicating most interfaces, if not implementations, or resort to non-trivial generics, or accept an unnecessary penalty for definite types, or push to the client the definite storage matter. There's simply no satisfying solution here [that I know of]. The duplication of every standard container to have both [in]definite variants is a strong indictment.

The only indefinite data structure that is needed seems to be holders. Any other 
indefinite data structure can be implemented as the equivalent definite data 
structure of holders, so there need be no duplication of implementations. That 
one cannot use a single pkg for both does result in duplication of the spec, but 
that seems like less of an issue to me.

-- 
Jeff Carter
"Apple juice and Darvon is fantastic together."
Play It Again, Sam
127

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

* Re: Calling inherited primitive operations in Ada
  2022-09-02  6:11                         ` Emmanuel Briot
@ 2022-09-02 10:55                           ` Jeffrey R.Carter
  2022-09-02 11:20                             ` Emmanuel Briot
  2022-09-03  0:07                           ` Randy Brukardt
  1 sibling, 1 reply; 37+ messages in thread
From: Jeffrey R.Carter @ 2022-09-02 10:55 UTC (permalink / raw)


On 2022-09-02 08:11, Emmanuel Briot wrote:
> 
> I did point you to the full repository if you prefer an extensive, real-life code sample. This was just an extract showing the gist of the issue.
> 
> One can check the full code and extensive documentation on the design in the github repository.

Yes, I looked at it, and found it over complicated, difficult to understand, and 
not user friendly. There appears to be extensive HTML documentation, but it can 
only be viewed as HTML source in Github, which is not easy to read, so I didn't.

Apparently a user who wants a map has to supply a significant part of what I 
consider the implementation of the map. As such, this may serve as a hidden 
layer to implement a library of data structures, but seems unusable for the 
typical user, for whom using a hashed-map abstraction should be as simple as

function Hash (Key : in Identifier) return Hash_Value;

package Maps is new Lib.Maps
    (Identifier => Identifier, Associated_Value => Associated_Value);

I was not willing to spend more than about 15 minutes trying to understand this, 
so I may be missing something.

> These packages are mostly implementation details. They are used to build high-level packages similar to the Ada containers

This agrees with what I was saying earlier. But even for such a use, simplicity 
and ease of understanding are still the most important aspects of S/W. If 
attaining them involves some code duplication they are worth that price.

>> that pkg Keys serves some actual role in the spec of Maps, then someone wanting
>> to use pkg Maps will need to understand that role, which involves understanding
>> Definite_Elements, which involves understanding pkg Traits, which involves
>> understanding Elements.
> 
> which involves understanding Ada, which involves understanding the compiler, which involves understanding the kernel sources, ...
> How many times have you checked the whole sources of the GNAT runtime to understand how they implemented the Ada containers ?

One understands a pkg by understanding its spec. I find it hard to believe that 
you could actually think that I meant one had to understand the implementation 
as well.

-- 
Jeff Carter
"Apple juice and Darvon is fantastic together."
Play It Again, Sam
127

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

* Re: Calling inherited primitive operations in Ada
  2022-09-02 10:41                           ` Jeffrey R.Carter
@ 2022-09-02 11:04                             ` Dmitry A. Kazakov
  2022-09-03  0:12                               ` Randy Brukardt
  0 siblings, 1 reply; 37+ messages in thread
From: Dmitry A. Kazakov @ 2022-09-02 11:04 UTC (permalink / raw)


On 2022-09-02 12:41, Jeffrey R.Carter wrote:

> The only indefinite data structure that is needed seems to be holders.

The language should support and encourage design that does not rely on 
memory pools.

In my view one of major advantages of Ada is that indefinite objects can 
be handled without resorting to hidden or explicit pointers to pools.

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

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

* Re: Calling inherited primitive operations in Ada
  2022-09-02 10:55                           ` Jeffrey R.Carter
@ 2022-09-02 11:20                             ` Emmanuel Briot
  2022-09-02 14:28                               ` Jeffrey R.Carter
  2022-09-03  0:16                               ` Randy Brukardt
  0 siblings, 2 replies; 37+ messages in thread
From: Emmanuel Briot @ 2022-09-02 11:20 UTC (permalink / raw)


> not user friendly. There appears to be extensive HTML documentation, but it can 
> only be viewed as HTML source in Github, which is not easy to read, so I didn't. 

Those are generated from the .rst files in docs_src/

> typical user, for whom using a hashed-map abstraction should be as simple as 
> 
> function Hash (Key : in Identifier) return Hash_Value; 
> package Maps is new Lib.Maps 
> (Identifier => Identifier, Associated_Value => Associated_Value); 

Maps are created as

   package Maps0 is new GAL.Maps.Def_Def_Unbounded
      (Integer,
       Element_Type => Integer,
       Hash => Test_Support.Hash,
       Container_Base_Type => GAL.Controlled_Base);

The only addition here is `Container_Base_Type`, and that's because the library is probable with SPARK, and the latter doesn't support controlled types.
And Ada doesn't support default values for the formal parameters of generics (another annoying limitation !)

> I was not willing to spend more than about 15 minutes trying to understand this, 
> so I may be missing something.

Fair enough. The library is really a set of experiments, mostly successful, and I think it might have been used for the implementation of the current
SPARK containers in GNAT, though I am not positive there.
I did look at the pragmARC components, and there you indeed chose to have a large number of similar-looking packages and code duplication. I guess
we'll have just to agree to disagree on the design approach there. But of course, users having choices is what makes an ecosystem interesting.

What I was really going after are graphs and their algorithms. In particular, I want those algorithms to work on any graph data structure provided it has
a number of primitive operations. In fact, the algorithm could also work when the graph is kind of implicit in the code, even if we do not have an actual
Graph object. And those this, you need generics.

A similar approach is what Rust uses all over the place with its traits, or what C++ Boost library uses for its graphs, too.

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

* Re: Calling inherited primitive operations in Ada
  2022-09-02 11:20                             ` Emmanuel Briot
@ 2022-09-02 14:28                               ` Jeffrey R.Carter
  2022-09-03  0:16                               ` Randy Brukardt
  1 sibling, 0 replies; 37+ messages in thread
From: Jeffrey R.Carter @ 2022-09-02 14:28 UTC (permalink / raw)


On 2022-09-02 13:20, Emmanuel Briot wrote:
> 
> Maps are created as
> 
>     package Maps0 is new GAL.Maps.Def_Def_Unbounded
>        (Integer,
>         Element_Type => Integer,
>         Hash => Test_Support.Hash,
>         Container_Base_Type => GAL.Controlled_Base);

Where is that? All I saw in my quick look were Maps, Maps.Generics, and Maps.Impl.

-- 
Jeff Carter
"Apple juice and Darvon is fantastic together."
Play It Again, Sam
127

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

* Re: Calling inherited primitive operations in Ada
  2022-09-02  8:35                         ` amo...@unizar.es
  2022-09-02  8:48                           ` Dmitry A. Kazakov
  2022-09-02 10:41                           ` Jeffrey R.Carter
@ 2022-09-03  0:01                           ` Randy Brukardt
  2022-09-05  8:53                             ` amo...@unizar.es
  2 siblings, 1 reply; 37+ messages in thread
From: Randy Brukardt @ 2022-09-03  0:01 UTC (permalink / raw)


"amo...@unizar.es" <amosteo@unizar.es> wrote in message 
news:672e9bc6-1e53-42cb-a339-9230ab949de9n@googlegroups.com...
On Thursday, September 1, 2022 at 11:33:47 PM UTC+2, Jeffrey R.Carter wrote:
> On 2022-09-01 20:54, Emmanuel Briot wrote:

>> As presented, this seems very over complicated. Elements and 
>> Definite_Elements
>> add no value, and this is just a complex way of writing

>Going in a tangent, and I guess you know perfectly well, but this is caused 
>by the
>painful duplication of code that Ada pushes you to by not having a native 
>way to
>abstract storage of definite vs indefinite types.

This is premature optimization at it's worst.

> So the provider of a generic library very soon faces this conundrum about
> duplicating most interfaces, if not implementations, or resort to 
> non-trivial
> generics, or accept an unnecessary penalty for definite types, or push to
> the client the definite storage matter.

There is no penalty in a code sharing implementation like Janus/Ada: the 
implementation of definite types is essentially the same as you would write 
by hand for an indefinite type. In most cases, all one needs is an 
indefinite generic.

(The plan for Janus/Ada was always to use post-compilation optimization to 
reduce the overhead of generics, but admittedly, that part never got built. 
If I had infinite time...)

Assuming otherwise is certainly premature optimization.

> There's simply no satisfying solution here [that I know of]. The 
> duplication of
> every standard container to have both [in]definite variants is a strong 
> indictment.

The original expectation for the containers was that there would be many 
variants of each container, because the needs for memory management, task 
management, and persistence differ between applications: there is no 
one-size fits all solution.

But I agree on one point: the "basic" container is unncessary; one should 
either use the indefinite or bounded container (depending on your memory 
management needs, either fully fixed or fully heap-based) -- stopping in the 
middle makes little sense.

                            Randy.


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

* Re: Calling inherited primitive operations in Ada
  2022-09-02  6:11                         ` Emmanuel Briot
  2022-09-02 10:55                           ` Jeffrey R.Carter
@ 2022-09-03  0:07                           ` Randy Brukardt
  2022-09-03  8:59                             ` Jeffrey R.Carter
  2022-09-03 19:00                             ` Simon Wright
  1 sibling, 2 replies; 37+ messages in thread
From: Randy Brukardt @ 2022-09-03  0:07 UTC (permalink / raw)


"Emmanuel Briot" <briot.emmanuel@gmail.com> wrote in message 
news:b678b499-0cb1-4c64-a88f-cfa9a79893e6n@googlegroups.com...

>These packages are mostly implementation details. They are used to build 
>high-level
>packages similar to the Ada containers, except with much better code reuse, 
>more
> efficient, and SPARK-provable.

(Wading in where I should probably not tread... :-)

But they violate the #1 principle of the Ada.Containers: ease of use. One 
principle that we insisted on was that a single instantiation was the 
maximum we would use, because we did not want people moving from arrays to 
containers to have to replace one declaration with a half page of magic 
incantations. (This is the reason that there is no container interface, for 
one consequence, and certainly no signature packages.)

In general, people either undertand and like signature packages, or really 
do not understand them and just use them when insisted on. The standard 
containers in Ada needed to be usable by the maximum number of users, and 
insisting on bells and whistles that many don't understand does not help.

                        Randy.




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

* Re: Calling inherited primitive operations in Ada
  2022-09-02 11:04                             ` Dmitry A. Kazakov
@ 2022-09-03  0:12                               ` Randy Brukardt
  2022-09-03  8:23                                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 37+ messages in thread
From: Randy Brukardt @ 2022-09-03  0:12 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:teso01$16gg$1@gioia.aioe.org...
> On 2022-09-02 12:41, Jeffrey R.Carter wrote:
>
>> The only indefinite data structure that is needed seems to be holders.
>
> The language should support and encourage design that does not rely on 
> memory pools.
>
> In my view one of major advantages of Ada is that indefinite objects can 
> be handled without resorting to hidden or explicit pointers to pools.

But they're implemented with some sort of hidden allocation. (GNAT uses a 
"secondary stack", whatever that is, but that is just a restricted form of 
pool). Janus/Ada uses built-in pools with cleanup for all such things to 
simplify the interface (the code for allocations and stand-alone objects is 
mostly shared, both within the compiler and at runtime).

                                Randy.


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

* Re: Calling inherited primitive operations in Ada
  2022-09-02 11:20                             ` Emmanuel Briot
  2022-09-02 14:28                               ` Jeffrey R.Carter
@ 2022-09-03  0:16                               ` Randy Brukardt
  1 sibling, 0 replies; 37+ messages in thread
From: Randy Brukardt @ 2022-09-03  0:16 UTC (permalink / raw)


"Emmanuel Briot" <briot.emmanuel@gmail.com> wrote in message 
news:bf352372-632c-45c1-b691-758756e87541n@googlegroups.com...
...
> And Ada doesn't support default values for the formal parameters of 
> generics (another annoying limitation !)

Ada *DOES* support default values for formal parameters of generics. At 
least the most used kinds of parameters, including subprograms and types 
(the latter added in Ada 2022). Whether GNAT (or your other favorite 
compiler) supports formal type defaults yet is a different question.

                                            Randy.


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

* Re: Calling inherited primitive operations in Ada
  2022-09-03  0:12                               ` Randy Brukardt
@ 2022-09-03  8:23                                 ` Dmitry A. Kazakov
  0 siblings, 0 replies; 37+ messages in thread
From: Dmitry A. Kazakov @ 2022-09-03  8:23 UTC (permalink / raw)


On 2022-09-03 02:12, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:teso01$16gg$1@gioia.aioe.org...
>> On 2022-09-02 12:41, Jeffrey R.Carter wrote:
>>
>>> The only indefinite data structure that is needed seems to be holders.
>>
>> The language should support and encourage design that does not rely on
>> memory pools.
>>
>> In my view one of major advantages of Ada is that indefinite objects can
>> be handled without resorting to hidden or explicit pointers to pools.
> 
> But they're implemented with some sort of hidden allocation. (GNAT uses a
> "secondary stack", whatever that is, but that is just a restricted form of
> pool). Janus/Ada uses built-in pools with cleanup for all such things to
> simplify the interface (the code for allocations and stand-alone objects is
> mostly shared, both within the compiler and at runtime).

For a programmer that does not matter. The problem with pools is 
locking, non-determinism, issues with protected actions. If secondary or 
primary stack is the program stack, nobody really cares.

BTW, merely doing pool tracing/bookkeeping becomes a sheer nightmare if 
you cannot return a string from a function.

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

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

* Re: Calling inherited primitive operations in Ada
  2022-09-03  0:07                           ` Randy Brukardt
@ 2022-09-03  8:59                             ` Jeffrey R.Carter
  2022-09-07  0:42                               ` Randy Brukardt
  2022-09-03 19:00                             ` Simon Wright
  1 sibling, 1 reply; 37+ messages in thread
From: Jeffrey R.Carter @ 2022-09-03  8:59 UTC (permalink / raw)


On 2022-09-03 02:07, Randy Brukardt wrote:
> 
> One
> principle that we insisted on was that a single instantiation was the
> maximum we would use

Except for queues

-- 
Jeff Carter
"In our experiments, the [Ada] compile[r] was able to find not
just typographical errors, but also conceptual errors in the
development of the code."
Scott and Bagheri
161

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

* Re: Calling inherited primitive operations in Ada
  2022-09-03  0:07                           ` Randy Brukardt
  2022-09-03  8:59                             ` Jeffrey R.Carter
@ 2022-09-03 19:00                             ` Simon Wright
  2022-09-05  6:56                               ` Emmanuel Briot
  1 sibling, 1 reply; 37+ messages in thread
From: Simon Wright @ 2022-09-03 19:00 UTC (permalink / raw)


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

> But they violate the #1 principle of the Ada.Containers: ease of
> use. One principle that we insisted on was that a single instantiation
> was the maximum we would use

And this was one reason that I didn't put up any arguments at Ada Europe
2002 for the Ada 95 Booch Components to form a basis for Ada.Containers
- you'd need 3 instantiations, one after the other.

--  A company's Fleet holds a number of Cars.

   with BC.Containers.Collections.Bounded;
   with Cars;
   package My_Fleet is

      use type Cars.Car;

      package Abstract_Car_Containers
      is new BC.Containers (Cars.Car);

      package Abstract_Car_Collections
      is new Abstract_Car_Containers.Collections;

      package Fleets
      is new Abstract_Car_Collections.Bounded (Maximum_Size => 30);

      The_Fleet : Fleets.Collection;

   end My_Fleet;

The other was a lack of consistency in the implementation (Length?
Size?).

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

* Re: Calling inherited primitive operations in Ada
  2022-09-03 19:00                             ` Simon Wright
@ 2022-09-05  6:56                               ` Emmanuel Briot
  2022-09-05  7:34                                 ` Dmitry A. Kazakov
                                                   ` (2 more replies)
  0 siblings, 3 replies; 37+ messages in thread
From: Emmanuel Briot @ 2022-09-05  6:56 UTC (permalink / raw)


Jeff Carter:
> Where is that? All I saw in my quick look were Maps, Maps.Generics, and Maps.Impl.

Simon Wright:
> And this was one reason that I didn't put up any arguments at Ada Europe
> 2002 for the Ada 95 Booch Components to form a basis for Ada.Containers
> - you'd need 3 instantiations, one after the other.

I definitely see the same issue. The way my library is trying to workaround that is as follows:
Those instantiations are only needed for people who want/need to control every aspects of their containers, for instance
how elements are stored, how/when memory is allocated, what is the growth strategy for vectors, and so on.
Most users should not have to care about that in practice. So we use code generation at compile time to generate
high-level packages similar to the Ada containers, with a limited set of formal parameters (in src/generated, to be
more specific). We can generate bounded/unbounded versions, definite/indefinite versions, and any combination of
those.
One of the intentions of the library, initially, had been the implementation of the Ada containers and SPARK containers
in GNAT, as a way to share as much code as possible between the two.


Randy Brukardt:
> Assuming otherwise is certainly premature optimization.

I am quoting a bit out of context, though I believe it is close enough. Designers of containers must care about performance
from the get-go. Otherwise, people might just as well use a list for everything and just traverse the list all the time. We all
know this would be way too inefficient, of course, which is why there are various sorts of containers.
Anyone who has actually written performance-sensitive code knows that memory allocations is definitely something to watch
out for, and the library design should definitely take that into account.

Jeff Carter:
> The only indefinite data structure that is needed seems to be holders

Although it is certainly true that using holders works, it is not applicable when designing a containers library that intends to be
mostly compatible with Ada containers. The latter have chosen, long ago and before Holder was a thing, to have definite and
indefinite versions. The main benefit to this approach is that users still retrieve directly the type they are interested in (e.g. String)
rather than a holder-to-string.
I must admit I have very limited experience with Holders, which I have never used in production code (nor, apparently, have my
colleagues and ex-colleagues). 


Randy Brukardt:
> Ada *DOES* support default values for formal parameters of generics

Hey, I just discovered that, thanks Randy ! For people who also did not know that:

    generic
         type Item_Count is range <>  or use Natural;
    package Gen is

It is supported by GNAT's newer versions (I don't know when it was implemented though)

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

* Re: Calling inherited primitive operations in Ada
  2022-09-05  6:56                               ` Emmanuel Briot
@ 2022-09-05  7:34                                 ` Dmitry A. Kazakov
  2022-09-05  9:30                                 ` Jeffrey R.Carter
  2022-09-07  0:51                                 ` Randy Brukardt
  2 siblings, 0 replies; 37+ messages in thread
From: Dmitry A. Kazakov @ 2022-09-05  7:34 UTC (permalink / raw)


On 2022-09-05 08:56, Emmanuel Briot wrote:

> Although it is certainly true that using holders works, it is not applicable when designing a containers library that intends to be
> mostly compatible with Ada containers.

Right. Holder requires finalization and finalization means language 
prescribed finalization lists which is highly undesirable in many cases.

> The main benefit to this approach is that users still retrieve directly the type they are interested in (e.g. String)
> rather than a holder-to-string.

And that the container designer has control over the pool where the 
items get actually allocated.

> I must admit I have very limited experience with Holders, which I have never used in production code (nor, apparently, have my
> colleagues and ex-colleagues).

I have been using the idea for a long time, since Ada 95 before the 
standard library had them. In my experience holders multiply the number 
of container variants:

1. Definite elements
2. Indefinite elements
    +
3. Holder elements in the interface (and maybe implementation)

The third gets a holder package as a formal parameter or, alternatively, 
is a child of a holder package (for performance reasons). The container 
interface has direct operations in terms of the Element_Type as well as 
in terms of the holder type.

Sometimes the holder variant is actually the indefinite one that 
promotes holders only in its interface.

P.S. In my opinion helper types/package is an evil of far greater scale 
than any premature optimization!

The programmers doing the latter at least try to understand the code 
they write.

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

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

* Re: Calling inherited primitive operations in Ada
  2022-09-03  0:01                           ` Randy Brukardt
@ 2022-09-05  8:53                             ` amo...@unizar.es
  0 siblings, 0 replies; 37+ messages in thread
From: amo...@unizar.es @ 2022-09-05  8:53 UTC (permalink / raw)


On Saturday, September 3, 2022 at 2:01:32 AM UTC+2, Randy Brukardt wrote:
> "amo...@unizar.es" <amo...@unizar.es> wrote in message 
> news:672e9bc6-1e53-42cb...@googlegroups.com...
> On Thursday, September 1, 2022 at 11:33:47 PM UTC+2, Jeffrey R.Carter wrote: 
> > On 2022-09-01 20:54, Emmanuel Briot wrote: 
> 
> >> As presented, this seems very over complicated. Elements and 
> >> Definite_Elements 
> >> add no value, and this is just a complex way of writing 
> 
> >Going in a tangent, and I guess you know perfectly well, but this is caused 
> >by the 
> >painful duplication of code that Ada pushes you to by not having a native 
> >way to 
> >abstract storage of definite vs indefinite types.

> This is premature optimization at it's worst.

Just because the language doesn't offer a way to do it. Otherwise I wouldn't need to care.

> > So the provider of a generic library very soon faces this conundrum about 
> > duplicating most interfaces, if not implementations, or resort to 
> > non-trivial 
> > generics, or accept an unnecessary penalty for definite types, or push to 
> > the client the definite storage matter.
> There is no penalty in a code sharing implementation like Janus/Ada: the 
> implementation of definite types is essentially the same as you would write 
> by hand for an indefinite type. In most cases, all one needs is an 
> indefinite generic. 

Well, that sounds neat for Janus/Ada, but is a different issue to clients having to wrap their indefinite types prior to instantiation, and suffer the unwrapping throughout the code.

> (The plan for Janus/Ada was always to use post-compilation optimization to 
> reduce the overhead of generics, but admittedly, that part never got built. 
> If I had infinite time...) 
> 
> Assuming otherwise is certainly premature optimization.

I'm of the opinion that it goes beyond just premature optimization, in the terrain of readability/maintainability by causing boilerplate, and when generics specializations do become necessary, by causing code duplication.

> > There's simply no satisfying solution here [that I know of]. The 
> > duplication of 
> > every standard container to have both [in]definite variants is a strong 
> > indictment.
> The original expectation for the containers was that there would be many 
> variants of each container, because the needs for memory management, task 
> management, and persistence differ between applications: there is no 
> one-size fits all solution. 
> 
> But I agree on one point: the "basic" container is unncessary; one should 
> either use the indefinite or bounded container (depending on your memory 
> management needs, either fully fixed or fully heap-based) -- stopping in the 
> middle makes little sense. 

That makes sense, right.

> 
> Randy.

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

* Re: Calling inherited primitive operations in Ada
  2022-09-05  6:56                               ` Emmanuel Briot
  2022-09-05  7:34                                 ` Dmitry A. Kazakov
@ 2022-09-05  9:30                                 ` Jeffrey R.Carter
  2022-09-07  0:51                                 ` Randy Brukardt
  2 siblings, 0 replies; 37+ messages in thread
From: Jeffrey R.Carter @ 2022-09-05  9:30 UTC (permalink / raw)


On 2022-09-05 08:56, Emmanuel Briot wrote:
> 
> I definitely see the same issue. The way my library is trying to workaround that is as follows:
> Those instantiations are only needed for people who want/need to control every aspects of their containers, for instance
> how elements are stored, how/when memory is allocated, what is the growth strategy for vectors, and so on.
> Most users should not have to care about that in practice. So we use code generation at compile time to generate
> high-level packages similar to the Ada containers, with a limited set of formal parameters (in src/generated, to be
> more specific). We can generate bounded/unbounded versions, definite/indefinite versions, and any combination of
> those.

This seems backwards. The user should encounter the forms most likely to be used 
first; if part of the packages are in a subdirectory, those should be the ones 
less likely for the typical user to use.

> Although it is certainly true that using holders works, it is not applicable when designing a containers library that intends to be
> mostly compatible with Ada containers. The latter have chosen, long ago and before Holder was a thing, to have definite and
> indefinite versions. The main benefit to this approach is that users still retrieve directly the type they are interested in (e.g. String)
> rather than a holder-to-string.

Before Ada.Containers existed, I commonly used definite data structures from the 
PragmARCs with Unbounded_String, which is partly a specialized holder for String 
(and partly a specialized Vector for Positive/Character). Generalizing from this 
led to implementing a Holder pkg.

When I said a holder is the only indefinite pkg that is needed, I meant to imply 
that other indefinite structures would be implemented using the definite form + 
holder.

-- 
Jeff Carter
“Bug rates in C++ are running higher even than C ...”
Stephen F. Zeigler
216

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

* Re: Calling inherited primitive operations in Ada
  2022-09-03  8:59                             ` Jeffrey R.Carter
@ 2022-09-07  0:42                               ` Randy Brukardt
  0 siblings, 0 replies; 37+ messages in thread
From: Randy Brukardt @ 2022-09-07  0:42 UTC (permalink / raw)


"Jeffrey R.Carter" <spam.jrcarter.not@spam.acm.org.not> wrote in message 
news:tev515$2rbj5$1@dont-email.me...
> On 2022-09-03 02:07, Randy Brukardt wrote:
>>
>> One
>> principle that we insisted on was that a single instantiation was the
>> maximum we would use
>
> Except for queues

Right, and one consequence of that is that the queues aren't used much. (Not 
sure if they would be used much in any case, they're definitely a 
specialized need compared to a map.)

                         Randy. 


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

* Re: Calling inherited primitive operations in Ada
  2022-09-05  6:56                               ` Emmanuel Briot
  2022-09-05  7:34                                 ` Dmitry A. Kazakov
  2022-09-05  9:30                                 ` Jeffrey R.Carter
@ 2022-09-07  0:51                                 ` Randy Brukardt
  2 siblings, 0 replies; 37+ messages in thread
From: Randy Brukardt @ 2022-09-07  0:51 UTC (permalink / raw)


"Emmanuel Briot" <briot.emmanuel@gmail.com> wrote in message 
news:458444ed-e384-4663-896c-bb38dae3c5cbn@googlegroups.com...
...
> Randy Brukardt:
>> Assuming otherwise is certainly premature optimization.
>
> I am quoting a bit out of context, though I believe it is close enough.
> Designers of containers must care about performance
> from the get-go. Otherwise, people might just as well use a list for
> everything and just traverse the list all the time. We all
> know this would be way too inefficient, of course, which is why there
> are various sorts of containers. Anyone who has actually written
> performance-sensitive code knows that memory allocations is definitely
> something to watch out for, and the library design should definitely take
> that into account.

Definitely out of context. If you have code which is truly performance 
sensitive, then it cannot also be portable Ada code. That's because of the 
wide variety of implementation techniques, especially for generics. (For 
Janus/Ada, if you have critical performance needs, you have to avoid the use 
of generics in those critical paths -- sharing overhead is non-zero.)

I agree that the design of the containers matters (which is why the we made 
the sets of operations for the various containers as close as possible, so 
switching containers is relatively easy). But the indefinite/definite thing 
is premature optimization - it makes little difference for a Janus/Ada 
generic, at least in the absence of the full-program optimizer (that we 
never built). If your code isn't intended to be portable Ada code, then 
*maybe* it makes sense to worry about such things. But the expectation was 
always that containers would be useful in cases where the performance is 
*not* critical - one probably should use a custom data structure for 
performance critical things. (But most things aren't really performance 
critical in reality.)

                                     Randy.


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

end of thread, other threads:[~2022-09-07  0:51 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-31  8:15 Calling inherited primitive operations in Ada Emmanuel Briot
2022-08-31 17:11 ` DrPi
2022-08-31 19:13 ` Dmitry A. Kazakov
2022-09-01  6:56   ` Emmanuel Briot
     [not found]     ` <67b32db0-c4db-466c-ac13-e597e008c762n@googlegroups.com>
2022-09-01 10:02       ` Dmitry A. Kazakov
2022-09-01 11:59       ` Jeffrey R.Carter
2022-09-01 12:37         ` Dmitry A. Kazakov
2022-09-01 13:37           ` Jeffrey R.Carter
2022-09-01 14:10             ` Emmanuel Briot
2022-09-01 15:50               ` amo...@unizar.es
2022-09-01 16:03               ` Jeffrey R.Carter
2022-09-01 16:07                 ` Emmanuel Briot
2022-09-01 16:17                   ` Jeffrey R.Carter
2022-09-01 18:54                     ` Emmanuel Briot
2022-09-01 21:33                       ` Jeffrey R.Carter
2022-09-02  6:11                         ` Emmanuel Briot
2022-09-02 10:55                           ` Jeffrey R.Carter
2022-09-02 11:20                             ` Emmanuel Briot
2022-09-02 14:28                               ` Jeffrey R.Carter
2022-09-03  0:16                               ` Randy Brukardt
2022-09-03  0:07                           ` Randy Brukardt
2022-09-03  8:59                             ` Jeffrey R.Carter
2022-09-07  0:42                               ` Randy Brukardt
2022-09-03 19:00                             ` Simon Wright
2022-09-05  6:56                               ` Emmanuel Briot
2022-09-05  7:34                                 ` Dmitry A. Kazakov
2022-09-05  9:30                                 ` Jeffrey R.Carter
2022-09-07  0:51                                 ` Randy Brukardt
2022-09-02  8:35                         ` amo...@unizar.es
2022-09-02  8:48                           ` Dmitry A. Kazakov
     [not found]                             ` <9484a755-f55d-407e-a40b-92421b0bcafbn@googlegroups.com>
2022-09-02  9:55                               ` Dmitry A. Kazakov
2022-09-02 10:41                           ` Jeffrey R.Carter
2022-09-02 11:04                             ` Dmitry A. Kazakov
2022-09-03  0:12                               ` Randy Brukardt
2022-09-03  8:23                                 ` Dmitry A. Kazakov
2022-09-03  0:01                           ` Randy Brukardt
2022-09-05  8:53                             ` amo...@unizar.es

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