comp.lang.ada
 help / color / mirror / Atom feed
* class wide iterable (and indexable)
@ 2019-01-02 15:48 George Shapovalov
  2019-01-02 17:39 ` Simon Wright
  2019-01-26 22:11 ` George Shapovalov
  0 siblings, 2 replies; 76+ messages in thread
From: George Shapovalov @ 2019-01-02 15:48 UTC (permalink / raw)


Hello,

I apologize if something like this is a common thing, but search here or on google does not turn up much of directly related info, and I cannot quite understand why the following confuses gnat..

The intention here is to create a top-level interface providing iterable/indexable, well, interface, with specific derived types providing appropriate data handling (say to let user select either dynamic, Ada.Containers.Vectors based, or fixed, based on plain arrays storage). 

See here for working code:
https://github.com/gerr135/ada_gems/tree/master/list_iface

So, I would have 
package Lists is ..
type List_Interface is interface
        with Constant_Indexing => List_Constant_Reference,
            Variable_Indexing => List_Reference,
            Default_Iterator  => Iterate,
            Iterator_Element  => Element_Type;

package Lists.Dynamic is ..
type List is new List_Interface with private ..

package Lists.Fixed is ..
type List is new List_Interface with private..

with all appropriate elements declared as abstract and derived types implementing them - either directly attaching Vector interface or wrapping around base array..

Then common code could be kept in class-wide methods, using the new loop forms, like in:
--
for item of List loop
  do_something(item);
end loop;
as well as direct indexing, i.e. List(i)
--
with specific storage types selected as needed in client procedures. In most optimistic scenario only declarative region would need light changes..

This all works well in fact, as long as I operate on specific types. But as soon as I try to use class-wide variable, the "of" form of the loop seems to confuse the compiler.
Thus, e.g. 

LL : Lists.Dynamic.List;
for l of LL loop .. -- works fine

but
LC : Lists.List_Interface'Class := Lists.Dynamic.To_Vector(5);
for l of LC loop .. -- confuses the compiler

And I just cannot see what's so special about this class-wide here. It all seems to follow exactly the same form (by design it passes all compiler checks up to this point).

Please see here for the code:
https://github.com/gerr135/ada_gems/tree/master/list_iface

the specific error is:
test_list_iface.adb:91:17: expected type "Standard.Integer"
test_list_iface.adb:91:17: found private type "Cursor" defined at lists.ads:32, instance at line 22
(and one more line further down that is clearly derivative)

This is not quite a 5-line example code, but implementing iterable/indexable interfaces with proper inheritance is somewhat beasty (even if its utility is in concise end-point code). I am afraid this is the minimal code that would illustrate the point (cut and reformed from larger project where I was trying such approach. Perhaps I should turn to iterating over some index type, which needs to be provided anyway. Seems to be simpler and as readable, but what is there the new interface for, if not to be tried out? :) ).

I would be thankful for any pointers, as I am at a loss what that class-wide for loop is getting confused about. Or why it even expects the Index type in the "of" loop?

Thank you for any pointers.

George

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

* Re: class wide iterable (and indexable)
  2019-01-02 15:48 class wide iterable (and indexable) George Shapovalov
@ 2019-01-02 17:39 ` Simon Wright
  2019-01-02 18:11   ` George Shapovalov
  2019-01-26 22:11 ` George Shapovalov
  1 sibling, 1 reply; 76+ messages in thread
From: Simon Wright @ 2019-01-02 17:39 UTC (permalink / raw)


George Shapovalov <gshapovalov@gmail.com> writes:

> I would be thankful for any pointers, as I am at a loss what that
> class-wide for loop is getting confused about. Or why it even expects
> the Index type in the "of" loop?

Compiling (a subsection of) your code with -gnatG, which lists the
generated expanded code in an Ada-like syntax, we get

      C2220b : test_list_iface__pl__cursor := T2232b!(
        test_list_iface__pl__list_iterator_interfaces__reversible_iteratorH!
        (I2224b).all (1)).all (I2224b);
      L_5 : while test_list_iface__pl__has_element (C2220b) loop
         n : test_list_iface__pl__element_type renames
           test_list_iface__pl__list_reference (lc, C2220b);
         ada__text_io__put__4 (n'img);
         C2220b :=
           $test_list_iface__pl__list_iterator_interfaces__next__2 (
           I2224b, C2220b);
      end loop L_5;

which shows that part of the code (correctly) expects an integer, while
another part provides a cursor; so you're right, the compiler is
confused, this is a compiler bug.

However, I think the issue may be that you've only defined one function
List_Reference: if you look at Ada.Containers.Vectors you'll see

   function Reference
     (Container : aliased in out Vector;
      Position  : Cursor) return Reference_Type;
   pragma Inline (Reference);
...
   function Reference
     (Container : aliased in out Vector;
      Index     : Index_Type) return Reference_Type;
   pragma Inline (Reference);

so GNAT's "bug" is that it doesn't understand how to cope with your
error. AdaCore are always interested in improving error messages, but
this error does seem rather out of the ordinary!

I had a quick-and-dirty go at fixing this, & got a build, but ended with

testing List_Interface'Class ..
assignin values .. done;  values: 
Catchpoint 1, CONSTRAINT_ERROR (Ada.Tags.Displace: invalid interface conversion) at 0x00000001000210da in test_list_iface.pld.iterate (container=..., 
    <iterateBIPalloc>=2, <iterateBIPstoragepool>=0x0, 
    <iterateBIPfinalizationmaster>=0x0, <iterateBIPaccess>=0x0)
    at /Users/simon/tmp/cla/ada_gems/list_iface/src/lists-dynamic.adb:46
46	        return List_Iterator_Interfaces.Reversible_Iterator'Class(ACV.Vector(Container).Iterate);
(gdb) l
41	--     end;
42	
43	    overriding
44	    function Iterate (Container : in List) return List_Iterator_Interfaces.Reversible_Iterator'Class is
45	    begin
46	        return List_Iterator_Interfaces.Reversible_Iterator'Class(ACV.Vector(Container).Iterate);
47	    end;
48	
49	end Lists.dynamic;

Hope this helps ...


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

* Re: class wide iterable (and indexable)
  2019-01-02 17:39 ` Simon Wright
@ 2019-01-02 18:11   ` George Shapovalov
  2019-01-03  8:52     ` Simon Wright
  2019-01-03 22:56     ` Randy Brukardt
  0 siblings, 2 replies; 76+ messages in thread
From: George Shapovalov @ 2019-01-02 18:11 UTC (permalink / raw)


Thanks!
I'll try adding this and see if I can get around that invalid interface conversion. 

I did see in the Ada.Containers.Vectors code two versions defined, however I was not clear on why, especially since both the Ada Gem 10x (I forgot now exact number) and Ada Rationale for 2012 seem to only provide one, with a Cursor. Besides, that seemed to work just fine when specific types are declared, only class-wide gave me trouble.. 
Interesting that indexing works fine, no confusion here (but of course it goes through other aspects, and there I had to change the name of the referenced function in derived type, otherwise the compiler was getting confused too - I left a comment in the code to this effect)..

However, from your response (also my general impression while digging through the iterables workings) is that this is not a common way to provide such code unification. How then one is supposed to go about such feature? 

On a related note, I was rather surprised that the related types in Ada.Containers do not form such a hierarchy. Say both Ada.Containers.Vectors and Indefinite_Vectors (and especially now with addition of Bounded_Vectors too) all could derive from a common ancestor that could be used to implement common functionality and let end user chose the desired data storage model..

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

* Re: class wide iterable (and indexable)
  2019-01-02 18:11   ` George Shapovalov
@ 2019-01-03  8:52     ` Simon Wright
  2019-01-03  9:30       ` George Shapovalov
  2019-01-04  4:32       ` Shark8
  2019-01-03 22:56     ` Randy Brukardt
  1 sibling, 2 replies; 76+ messages in thread
From: Simon Wright @ 2019-01-03  8:52 UTC (permalink / raw)


George Shapovalov <gshapovalov@gmail.com> writes:

> Thanks!
> I'll try adding this and see if I can get around that invalid
> interface conversion.
>
> I did see in the Ada.Containers.Vectors code two versions defined,
> however I was not clear on why, especially since both the Ada Gem 10x
> (I forgot now exact number) and Ada Rationale for 2012 seem to only
> provide one, with a Cursor.

ARM A.18.2(34.3)ff[1] has both forms.

> However, from your response (also my general impression while digging
> through the iterables workings) is that this is not a common way to
> provide such code unification. How then one is supposed to go about
> such feature?

You might be interested in Emmanuel's 'traits'-based containers, see
[2], [3].

> On a related note, I was rather surprised that the related types in
> Ada.Containers do not form such a hierarchy. Say both
> Ada.Containers.Vectors and Indefinite_Vectors (and especially now with
> addition of Bounded_Vectors too) all could derive from a common
> ancestor that could be used to implement common functionality and let
> end user chose the desired data storage model..

The Ada 95 Booch Components[4] follow this model. One reason they
weren't taken as a model for Ada.Containers was that the model requires
multiple levels of generic instantiation of child packages: for example,
to make an unbounded map from Unbounded_String to Unbounded_String
requires

   with Ada.Strings.Unbounded;
   with BC.Containers.Maps.Unbounded;
   with BC.Support.Standard_Storage;

   package Configuration_Demo_Support is

      package Abstract_String_Containers is new BC.Containers
        (Item => Ada.Strings.Unbounded.Unbounded_String,
         "=" => Ada.Strings.Unbounded."=");

      package Abstract_String_Maps
      is new Abstract_String_Containers.Maps
        (Key => Ada.Strings.Unbounded.Unbounded_String,
         "=" => Ada.Strings.Unbounded."=");

      function Hash (S : Ada.Strings.Unbounded.Unbounded_String)
        return Natural;

      package String_Maps
      is new Abstract_String_Maps.Unbounded
        (Hash => Hash,
         Buckets => 43,
         Storage => BC.Support.Standard_Storage.Pool);

   end Configuration_Demo_Support;

[1] http://www.ada-auth.org/standards/rm12_w_tc1/html/RM-A-18-2.html#p34.3
[2] https://blog.adacore.com/traits-based-containers
[3] https://github.com/AdaCore/ada-traits-containers
[4] https://sourceforge.net/projects/booch95/


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

* Re: class wide iterable (and indexable)
  2019-01-03  8:52     ` Simon Wright
@ 2019-01-03  9:30       ` George Shapovalov
  2019-01-03 16:45         ` Jeffrey R. Carter
  2019-01-04  4:32       ` Shark8
  1 sibling, 1 reply; 76+ messages in thread
From: George Shapovalov @ 2019-01-03  9:30 UTC (permalink / raw)


> ARM A.18.2(34.3)ff[1] has both forms.
Ah, thank you for the pointer. Unfortunately ARM is a rather heavy reading, targeted more at language implementation (so, not the first place to look at if there are other sources). But I guess I enter this territory already while trying to reimplement indexing and iteration..

> You might be interested in Emmanuel's 'traits'-based containers, see
> [2], [3].
Thanks, I'll take a look.

> The Ada 95 Booch Components[4] follow this model. One reason they
> weren't taken as a model for Ada.Containers was that the model requires
> multiple levels of generic instantiation of child packages:
Yes, I am very well aware of that :) (and I used Booch components before, this is also why surprise, as Ada.Containers seem to be rather inspired by them).
However here we have the trade-off of an extra few clear lines of code (most commonly one trivial would suffice I suspect) for the capability to do a more "universal" algorithm implementation. I'd say it is well worth it, but apparently this was not the majority opinion..

Thanks again for all the pointers!
George



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

* Re: class wide iterable (and indexable)
  2019-01-03  9:30       ` George Shapovalov
@ 2019-01-03 16:45         ` Jeffrey R. Carter
  0 siblings, 0 replies; 76+ messages in thread
From: Jeffrey R. Carter @ 2019-01-03 16:45 UTC (permalink / raw)


On 1/3/19 10:30 AM, George Shapovalov wrote:
>> ARM A.18.2(34.3)ff[1] has both forms.
> Ah, thank you for the pointer. Unfortunately ARM is a rather heavy reading, targeted more at language implementation (so, not the first place to look at if there are other sources). But I guess I enter this territory already while trying to reimplement indexing and iteration..

This is true of much of the ARM, but not of Annex A, which is required reading 
for anyone using Ada.

-- 
Jeff Carter
"Of course, one couldn't think properly in Paris--
it was so uncomfortable and the houses were
central heated."
Clouds of Witness
153

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

* Re: class wide iterable (and indexable)
  2019-01-02 18:11   ` George Shapovalov
  2019-01-03  8:52     ` Simon Wright
@ 2019-01-03 22:56     ` Randy Brukardt
  2019-01-04  0:00       ` George Shapovalov
  1 sibling, 1 reply; 76+ messages in thread
From: Randy Brukardt @ 2019-01-03 22:56 UTC (permalink / raw)


"George Shapovalov" <gshapovalov@gmail.com> wrote in message 
news:2a6929c5-72fa-4d84-953a-44ea4597ab38@googlegroups.com...
...
>I did see in the Ada.Containers.Vectors code two versions defined, however 
>I was not
>clear on why, especially since both the Ada Gem 10x (I forgot now exact 
>number) and
>Ada Rationale for 2012 seem to only provide one, with a Cursor.

Vectors support both indexing by an integer and reference via a cursor. 
Usually, the List container is a better example for cursor operations 
because it doesn't have the confusion of (direct) indexing involved.

...
>On a related note, I was rather surprised that the related types in 
>Ada.Containers do not
>form such a hierarchy. Say both Ada.Containers.Vectors and 
>Indefinite_Vectors (and
>especially now with addition of Bounded_Vectors too) all could derive from 
>a common
>ancestor that could be used to implement common functionality and let end 
>user chose
>the desired data storage model..

Because that would substantially harm ease-of-use. You'd have to write 
multiple instantiations to create any container. It's annoying enough (to 
some, at least) to have to write one.

Besides, interfaces are (nearly) useless (and especially so for this sort of 
usage, where some part has to be generic). They add a lot of runtime 
overhead that doesn't actually get used in real programs. For example, we 
did do what you suggest for the queue containers. Irrelevant thought: that's 
probably why I have yet to hear of anyone actually using one of them. :-) 
Back to the point: there's virtually no circumstance where you'd use more 
than one type of queue with any specific data type, so the generality buys 
essentially nothing. (The only real use is in generic units, but those could 
have been handled with formal packages just as well.) So you're paying a 
substantial price in code size and time, but no real gain.

Perhaps if Ada allowed multiple controlling parameters of different tagged 
types, then there might be more use. But with the existing Ada rules, 
interfaces can only be useful if the profiles are fixed (non-generic) and 
are still reusable -- that doesn't happen that often.

                               Randy.





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

* Re: class wide iterable (and indexable)
  2019-01-03 22:56     ` Randy Brukardt
@ 2019-01-04  0:00       ` George Shapovalov
  2019-01-04  8:43         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 76+ messages in thread
From: George Shapovalov @ 2019-01-04  0:00 UTC (permalink / raw)


> Vectors support both indexing by an integer and reference via a cursor. 
> Usually, the List container is a better example for cursor operations 
> because it doesn't have the confusion of (direct) indexing involved.
Ah, right, that Ada gem I initially read was indeed operating on linked lists. This is why it only implemented one method. But I needed the indexing too in my case, which is attached via different aspects. So it all seemed to correspond so far and even work, as long as I did not try to do an "of-loop" over class-wide var (derived types worked fine).


> Because that would substantially harm ease-of-use. You'd have to write 
> multiple instantiations to create any container. It's annoying enough (to 
> some, at least) to have to write one.
Well, I rather consider an extra line of (typically elementary) code a small price for versatility, but then apparently opinions vary a lot on this one :). 
But the next point is more essential:

 
> Besides, interfaces are (nearly) useless (and especially so for this sort of 
> usage, where some part has to be generic). They add a lot of runtime 
> overhead that doesn't actually get used in real programs.
Really? I did not consider this. I thought there would be no extra overhead, as the compiler should be able to select appropriate constructs as needed and optimize away with higher -OX. But indeed, in case of generics it would likely produce extra code blobs.. Oh, well, looks like I may be better off with a more simplistic design, using getters/setters and iterating over the provided index type (which is needed there anyway). Looks like that would be more efficient with generics, even though less elegant. Those extra get/set qualifiers instead of direct indexed access look a bit annoying :). But this is really a minor issue. And at least I learned a thing or two about inner gnat workings on the way :).

> Perhaps if Ada allowed multiple controlling parameters of different tagged 
> types, then there might be more use.
Funny that you mention this one. That was my thought exactly at one (completely unrelated) point - that unlike most other languages, Ada has the syntax that could naturally allow multiple controlling parameters, and that could be a really powerful type composition feature.. A pity this was not done so, that would be a fun feature. But then I do realize that it takes a special kind of thought organization (more pure math than typical procedural idiom most programmers follow) for the developer to feel comfortable with such a feature. With most other common languages not having even a provision to formulate such a structure, most developers would be at a loss to comprehend what is even proposed in the standard I am afraid (at least from what I could observe). So I can see why this was not seriously considered. Plus that would give a huge potential for abuse - just think of all the possible combinations multiplying complexity, having to turn simple dispatch tables into multidimensional (and very sparse) arrays..

Btw, I'd rather say that this, and not the (not so evident) observation of extra overhead is the main reason for:
> For example, we 
> did do what you suggest for the queue containers. Irrelevant thought: that's 
> probably why I have yet to hear of anyone actually using one of them. :-) 
That, and (more essentially) that the standard Ada.Containers are sufficient for most situations, as you point out elsewhere.


> But with the existing Ada rules, 
> interfaces can only be useful if the profiles are fixed (non-generic) and 
> are still reusable -- that doesn't happen that often.
Why? 
Besides the optimization issues, which are invisible to end user and often are not so critical, I fail to see how generics would affect logical structure of the program in this case. Besides linking various type hierarchies together, interfaces are good for containing common code that does not care about specific data storage details. How generics complicate the issue? (at the level of program logic, not underlying code - most apps away from critical domains do not care about 2x size or loss of 10% time efficiency away from critical loops, if that allows to reuse well tested code). In fact it seems to me that generics fit very well with such development model..


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

* Re: class wide iterable (and indexable)
  2019-01-03  8:52     ` Simon Wright
  2019-01-03  9:30       ` George Shapovalov
@ 2019-01-04  4:32       ` Shark8
  2019-01-05  9:03         ` Randy Brukardt
  1 sibling, 1 reply; 76+ messages in thread
From: Shark8 @ 2019-01-04  4:32 UTC (permalink / raw)


On Thursday, January 3, 2019 at 1:52:50 AM UTC-7, Simon Wright wrote:
> 
> 
> The Ada 95 Booch Components[4] follow this model. One reason they
> weren't taken as a model for Ada.Containers was that the model requires
> multiple levels of generic instantiation of child packages: for example,
> to make an unbounded map from Unbounded_String to Unbounded_String
> requires
> 
>    with Ada.Strings.Unbounded;
>    with BC.Containers.Maps.Unbounded;
>    with BC.Support.Standard_Storage;
> 
>    package Configuration_Demo_Support is
> 
>       package Abstract_String_Containers is new BC.Containers
>         (Item => Ada.Strings.Unbounded.Unbounded_String,
>          "=" => Ada.Strings.Unbounded."=");
> 
>       package Abstract_String_Maps
>       is new Abstract_String_Containers.Maps
>         (Key => Ada.Strings.Unbounded.Unbounded_String,
>          "=" => Ada.Strings.Unbounded."=");
True; but the Automatic Instantiation AI would relieve a lot of the hassle here -- http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0268-1.txt?rev=1.2  

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

* Re: class wide iterable (and indexable)
  2019-01-04  0:00       ` George Shapovalov
@ 2019-01-04  8:43         ` Dmitry A. Kazakov
  2019-01-04 12:20           ` George Shapovalov
  2019-01-05  9:21           ` Randy Brukardt
  0 siblings, 2 replies; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-04  8:43 UTC (permalink / raw)


On 2019-01-04 01:00, George Shapovalov wrote:

>> Besides, interfaces are (nearly) useless (and especially so for this sort of
>> usage, where some part has to be generic). They add a lot of runtime
>> overhead that doesn't actually get used in real programs.
> Really?

I am using interfaces extensively and in real programs. (:-))

> I did not consider this. I thought there would be no extra overhead, as the compiler should be able to select appropriate constructs as needed and optimize away with higher -OX.

In real programs dispatch is rare, thus there is no overhead. I don't 
know which overhead Randy meant, though. Maybe, space overhead? That is 
not nearly close to what generics produce in GNAT...

>> Perhaps if Ada allowed multiple controlling parameters of different tagged
>> types, then there might be more use.
> Funny that you mention this one. That was my thought exactly at one (completely unrelated) point - that unlike most other languages, Ada has the syntax that could naturally allow multiple controlling parameters, and that could be a really powerful type composition feature..

Huh, it would render generics useless! That would sadden a lot of 
people... (:-))

Alas, nobody knows how to make multiple dispatch safe while usable in 
independent packages. The case is when you derive from the types of the 
hierarchies in independently developed packages.

> A pity this was not done so, that would be a fun feature. But then I do realize that it takes a special kind of thought organization (more pure math than typical procedural idiom most programmers follow) for the developer to feel comfortable with such a feature. With most other common languages not having even a provision to formulate such a structure, most developers would be at a loss to comprehend what is even proposed in the standard I am afraid (at least from what I could observe).

Huh, most developers are at loss with generic instances they produce.

> So I can see why this was not seriously considered. Plus that would give a huge potential for abuse - just think of all the possible combinations multiplying complexity, having to turn simple dispatch tables into multidimensional (and very sparse) arrays..

No. However in the case of multiple dispatch you rarely can inherit 
safely. You would be required to override a lot, so the table would not 
be sparse.

>> But with the existing Ada rules,
>> interfaces can only be useful if the profiles are fixed (non-generic) and
>> are still reusable -- that doesn't happen that often.

Combination of interfaces and generics is the only way to handle many 
situations in practice. Actually it is a very frequent pattern when a 
base type is a formal parameter of some generic used to derive from it 
while adding implementations.

> Besides the optimization issues, which are invisible to end user and often are not so critical, I fail to see how generics would affect logical structure of the program in this case.

As all preprocessors generics tend to destroy any logic and every design 
by muddying mapping of the program types and modules to the 
problem-space entities.

> Besides linking various type hierarchies together, interfaces are good for containing common code that does not care about specific data storage details.

No, interfaces cannot contain common code except for class-wide one. Is 
that what Randy meant about overhead? This is another Ada problem that 
multiple inheritance is not fully supported. If it were, you could 
indeed have common code in the form of inherited bodies. But you cannot. 
Thus to overcome this language design fault we use the generic pattern I 
mentioned above:

    generic
       type Base is interface ...;
    package Poor_Mans_Inheritance;
       type Instance is new Base with ...;
       overriding procedure Inherit_Me_Please (X : in out Instance);
    end Poor_Mans_Inheritance;

    type My_Type_I_Cannot_Use_Yet is new Base with ...;
    package Generic_Mess is
       new Poor_Mans_Inheritance (My_Type_I_Cannot_Use_Yet);
    type My_Type is new Generic_Mess.Instance with null record;

> How generics complicate the issue?

It is hideous.

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


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

* Re: class wide iterable (and indexable)
  2019-01-04  8:43         ` Dmitry A. Kazakov
@ 2019-01-04 12:20           ` George Shapovalov
  2019-01-05 23:29             ` Jere
  2019-01-05  9:21           ` Randy Brukardt
  1 sibling, 1 reply; 76+ messages in thread
From: George Shapovalov @ 2019-01-04 12:20 UTC (permalink / raw)


> I am using interfaces extensively and in real programs. (:-))
Nice to know I am not such an exception :).

> In real programs dispatch is rare, thus there is no overhead. I don't 
> know which overhead Randy meant, though. Maybe, space overhead? That is 
> not nearly close to what generics produce in GNAT...
Ah, good. I was trying to imagine how it could be so bad indeed. So, thanks for confirming the sanity :).

> 
> >> Perhaps if Ada allowed multiple controlling parameters of different tagged
[..] 
> Huh, it would render generics useless! 
How so? Perhaps in the sense that the same effect could be achieved by different means, that yes of course. But anything Turing complete can emulate any other such thing anyway (albeit often grossly ugly). So, there is no need for anything but 4 base ops anyway :). But generics would retain their use as a concise and clear form of, well, generics in any case. One of 
 the main features that make Ada stand out is its expressivity, and clear and powerful generics are an important component here IMHO (at least as they were intended - to clarify further comments). Especially compared to glorified macros in the form of templates in C++ or similar. Having had to fight those, it is easy to appreciate clear (and much more verifiable) form of generics in Ada after that..

> >> But with the existing Ada rules,
> >> interfaces can only be useful if the profiles are fixed (non-generic) and
> >> are still reusable -- that doesn't happen that often.
> 
> Combination of interfaces and generics is the only way to handle many 
> situations in practice. Actually it is a very frequent pattern when a 
> base type is a formal parameter of some generic used to derive from it 
> while adding implementations.
Ah, I see now what you have meant about generics becoming useless. Yes, that use case would indeed be much alleviated by a less limited multiple inheritance, although that could create many more safety concerns I imagine (even though this field has been heavily trotted by now, with major languages allowing "full" multiple inheritance settling on specific and very strict rules of field/method lookup, most commonly based on topological sort). 


> > Besides the optimization issues, which are invisible to end user and often are not so critical, I fail to see how generics would affect logical structure of the program in this case.
> 
> As all preprocessors generics tend to destroy any logic and every design 
> by muddying mapping of the program types and modules to the 
> problem-space entities.
This would be the case with e.g. C++ templates, where it is often indeed necessary to meddle with "processed code" to comprehend what is going on and make sense of the 100-line long error message(for a single line of code) spit out by the compiler. Fortunately this is much more rare with Ada. Although this case is seemingly indeed one of those, so there then :).

> > Besides linking various type hierarchies together, interfaces are good for containing common code that does not care about specific data storage details.
> 
> No, interfaces cannot contain common code except for class-wide one. 
Yes, I have meant the class-wide methods here of course. Although I must admit I wished more than once that non null/abstract methods that could be inherited and overriden are allowed.  Of course they could only reference other methods (as the data is non-existent at this point), all eventually operating on the abstract/null primitives that are essentially "axioms" of the specific interface. But thus one could provide meaningful abstracted functionality that could be overriden in a sane way, removing the need for  various tricks, one of which you show in your comment. 
Perhaps allowing this and stopping at interfaces (vs full type multi-inheritance) would make for a sufficient but safe type system..

> > How generics complicate the issue?
> 
> It is hideous.
Well, in view of this part of discussion I must agree on this aspect, even if the intended use of generics is rather elegant (compared with most existing alternatives in other languages).

But alas, while it is fun to discuss language design issues, this grew way out of proportion with relation to the original issue by now :).
Still, thank you everybody for the informative answers and for the possibility to learn new things about inner workings of gnat..

George


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

* Re: class wide iterable (and indexable)
  2019-01-04  4:32       ` Shark8
@ 2019-01-05  9:03         ` Randy Brukardt
  0 siblings, 0 replies; 76+ messages in thread
From: Randy Brukardt @ 2019-01-05  9:03 UTC (permalink / raw)


"Shark8" <onewingedshark@gmail.com> wrote in message 
news:95f6a9b0-adc6-4044-8ff8-f0820612aeea@googlegroups.com...
> On Thursday, January 3, 2019 at 1:52:50 AM UTC-7, Simon Wright wrote:
>>
>>
>> The Ada 95 Booch Components[4] follow this model. One reason they
>> weren't taken as a model for Ada.Containers was that the model requires
>> multiple levels of generic instantiation of child packages: for example,
>> to make an unbounded map from Unbounded_String to Unbounded_String
>> requires
>>
>>    with Ada.Strings.Unbounded;
>>    with BC.Containers.Maps.Unbounded;
>>    with BC.Support.Standard_Storage;
>>
>>    package Configuration_Demo_Support is
>>
>>       package Abstract_String_Containers is new BC.Containers
>>         (Item => Ada.Strings.Unbounded.Unbounded_String,
>>          "=" => Ada.Strings.Unbounded."=");
>>
>>       package Abstract_String_Maps
>>       is new Abstract_String_Containers.Maps
>>         (Key => Ada.Strings.Unbounded.Unbounded_String,
>>          "=" => Ada.Strings.Unbounded."=");
> True; but the Automatic Instantiation AI would relieve a lot of the hassle 
> here --  
> http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0268-1.txt?rev=1.2

The AI you refer to is only about formal packages, while the above doesn't 
have any formal packages so I fail to see how it would help.

A more general automatic instantiation mechanism was also proposed in 
AI12-0215-1. But that one is a dead-body issue for me (at least as 
proposed). Ada gives specific places where every declaration occurs 
(statically) and is elaborated (dynamically). AI12-0215-1 throws that 
property completely away, harming analyzability, readability, and 
understandability -- it would be much like saying that there's no neeed to 
declare objects before using them because the compiler can figure out what 
was intended. Bah humbug. :-)

                            Randy.


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

* Re: class wide iterable (and indexable)
  2019-01-04  8:43         ` Dmitry A. Kazakov
  2019-01-04 12:20           ` George Shapovalov
@ 2019-01-05  9:21           ` Randy Brukardt
  2019-01-05 10:07             ` Dmitry A. Kazakov
                               ` (2 more replies)
  1 sibling, 3 replies; 76+ messages in thread
From: Randy Brukardt @ 2019-01-05  9:21 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:q0n6av$1tqs$1@gioia.aioe.org...
...
> In real programs dispatch is rare, thus there is no overhead.

This is probably true, but then interfaces are even more useless (they 
provide nothing that could possibly be of value other than dispatch!).

> I don't know which overhead Randy meant, though. Maybe, space overhead? 
> That is not nearly close to what generics produce in GNAT...

Dispatching is very expensive for interfaces, in that some form of search is 
needed. (Note: I have no idea how GNAT implements them exactly.) It might be 
possible to do some sort of link-time assignment of interface identifiers 
and link-time tag construction to avoid some of that cost (at the cost of a 
lot of space), but that would be such a complex and unusual project 
(conventional linkers don't support anything like that) that I've always 
considered it impraactical.

...
> No, interfaces cannot contain common code except for class-wide one. Is 
> that what Randy meant about overhead?

Not really. My main point is that you'll never have more than one concrete 
instance of a generic interface in any individual program (certainly not of 
an interface like that of a container), so all you're doing is paying a lot 
of overhead to use dispatching to that one concrete instance. You're better 
off (esp. in non-Janus/Ada compilers) using a formal package for that, as 
there's no runtime overhead involved. Even in Janus/Ada, there isn't much 
extra overhead (a formal package is just the formal descriptor block for the 
appropriate instance, so the overhead is the same as any normal generic).

Note: I mean one concrete type, there might be many objects of that type. 
But it doesn't make sense to use bounded and indefinite containers at the 
same time for the same element type. So an interface buys you very little. 
As Dmitry noted, you'd still have to pass the interface into a generic if 
you want any shared code. But you could have just passed the instance of the 
container into the generic and get the same sort of sharing.

Dmitry is of course an all-interface all the time sort of guy. All I see 
from that is a vast amount of typing to get nothing in particular in return. 
[But I'm not much of a fan of OOP, either; the big advantage of OOP is 
requiring few recompiles when adding features. That was a big deal in 1990, 
but it hardly matters today. (I can recompile the entirety of Janus/Ada - 
250,000 lines - in 15 minutes or so. Why try to save compiles?) And for 
that, you get to type dozens and dozens of declarations to do anything. 
While the supposedly terrible case statement solution gives you case 
completeness checks, variant checks, and essentially has no more chance of 
failure (and costs a lot less, and keeps all of the similar code together 
rather that scattering it about to every different kind of object).]

                                 Randy.



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

* Re: class wide iterable (and indexable)
  2019-01-05  9:21           ` Randy Brukardt
@ 2019-01-05 10:07             ` Dmitry A. Kazakov
  2019-01-05 18:17               ` George Shapovalov
  2019-01-07 21:07               ` Randy Brukardt
  2019-01-05 17:05             ` Jeffrey R. Carter
  2019-01-05 20:46             ` Shark8
  2 siblings, 2 replies; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-05 10:07 UTC (permalink / raw)


On 2019-01-05 10:21, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:q0n6av$1tqs$1@gioia.aioe.org...
> ...
>> In real programs dispatch is rare, thus there is no overhead.
> 
> This is probably true, but then interfaces are even more useless (they
> provide nothing that could possibly be of value other than dispatch!).

 From the SW design POV they provide a description of an interface, 
which is a lot of value as is.

>> I don't know which overhead Randy meant, though. Maybe, space overhead?
>> That is not nearly close to what generics produce in GNAT...
> 
> Dispatching is very expensive for interfaces, in that some form of search is
> needed. (Note: I have no idea how GNAT implements them exactly.) It might be
> possible to do some sort of link-time assignment of interface identifiers
> and link-time tag construction to avoid some of that cost (at the cost of a
> lot of space), but that would be such a complex and unusual project
> (conventional linkers don't support anything like that) that I've always
> considered it impraactical.

Bounded time dispatch must be a requirement of course. However I doubt 
that what we have now, a myriad of helper tagged types and objects 
created and destroyed all the time is more effective in any thinkable way.

> ...
>> No, interfaces cannot contain common code except for class-wide one. Is
>> that what Randy meant about overhead?
> 
> Not really. My main point is that you'll never have more than one concrete
> instance of a generic interface in any individual program (certainly not of
> an interface like that of a container),

I don't understand this. Usually I have dozens of instantiations of the 
same generics with different actual parameters.

> Note: I mean one concrete type, there might be many objects of that type.
> But it doesn't make sense to use bounded and indefinite containers at the
> same time for the same element type.

Of course it does. The best example is Ada strings, a container of 
characters. Practically every program in effect uses both bounded and 
unbounded strings, the later, maybe, in the form of access String (I 
tend to avoid Unbounded_String).

> Dmitry is of course an all-interface all the time sort of guy. All I see
> from that is a vast amount of typing to get nothing in particular in return.

You get type safety. Otherwise you can always go back K&R C! (:-))

> [But I'm not much of a fan of OOP, either; the big advantage of OOP is
> requiring few recompiles when adding features. That was a big deal in 1990,
> but it hardly matters today. (I can recompile the entirety of Janus/Ada -
> 250,000 lines - in 15 minutes or so. Why try to save compiles?) And for
> that, you get to type dozens and dozens of declarations to do anything.

That is because compilers are no longer large software, not even 
medium-size (:-)). My current project takes a half of week to recompile 
from scratch [*].

And recompilation is not the biggest problem. Deployment of the modules is.

> While the supposedly terrible case statement solution gives you case
> completeness checks, variant checks, and essentially has no more chance of
> failure (and costs a lot less, and keeps all of the similar code together
> rather that scattering it about to every different kind of object).

The main problem is that the "similar" code logically has nothing in 
common, except the shared interface. It must be written by different 
teams, at different locations and time. Independently tested, used, 
deployed, versioned, maintained. The case-statement solution crushes not 
only the architecture but all software process.

----------------------
* GNAT is awfully slow when compiling specifically generic 
instantiations, and I have lots of them. The more I have, the more I 
hate them.

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


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

* Re: class wide iterable (and indexable)
  2019-01-05  9:21           ` Randy Brukardt
  2019-01-05 10:07             ` Dmitry A. Kazakov
@ 2019-01-05 17:05             ` Jeffrey R. Carter
  2019-01-05 20:18               ` Dmitry A. Kazakov
  2019-01-05 21:09               ` Shark8
  2019-01-05 20:46             ` Shark8
  2 siblings, 2 replies; 76+ messages in thread
From: Jeffrey R. Carter @ 2019-01-05 17:05 UTC (permalink / raw)


On 1/5/19 10:21 AM, Randy Brukardt wrote:
> 
> Dmitry is of course an all-interface all the time sort of guy. All I see
> from that is a vast amount of typing to get nothing in particular in return.
> [But I'm not much of a fan of OOP, either; the big advantage of OOP is
> requiring few recompiles when adding features. That was a big deal in 1990,
> but it hardly matters today. (I can recompile the entirety of Janus/Ada -
> 250,000 lines - in 15 minutes or so. Why try to save compiles?) And for
> that, you get to type dozens and dozens of declarations to do anything.
> While the supposedly terrible case statement solution gives you case
> completeness checks, variant checks, and essentially has no more chance of
> failure (and costs a lot less, and keeps all of the similar code together
> rather that scattering it about to every different kind of object).]

A major problem with programming by extension is that it requires violating the 
S/W-engineering principle of locality. S/W engineers don't willingly violate 
those principles, so we can conclude that those who like programming by 
extension are not S/W engineers.

-- 
Jeff Carter
"What's special about Agile is that it's a mix of the
best and the worst."
Bertrand Meyer
148


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

* Re: class wide iterable (and indexable)
  2019-01-05 10:07             ` Dmitry A. Kazakov
@ 2019-01-05 18:17               ` George Shapovalov
  2019-01-05 20:07                 ` Simon Wright
  2019-01-07 21:07               ` Randy Brukardt
  1 sibling, 1 reply; 76+ messages in thread
From: George Shapovalov @ 2019-01-05 18:17 UTC (permalink / raw)


On Saturday, January 5, 2019 at 11:07:57 AM UTC+1, Dmitry A. Kazakov wrote:
> That is because compilers are no longer large software, not even 
> medium-size (:-)). My current project takes a half of week to recompile 
> from scratch.
Sorry to break up this "high opinions" discussion, it is as usual interesting to see varying points of view. Incidentally, having done a few long-standing projects and having maintained Ada in Gentoo Linux (which, in Gentoo's case, implies digging deep into gcc toolchain inner workings), I am of similar to Drmitry's opinion on this point (even though gcc, while bigger than Janus Ada, is still is nowhere near that kind of scale of course).

Nonetheless, back to the original point.
A small update on the original issue:

I have finally had some time to wrap my head around this issue a bit more and I have completed the implementation. Now it builds and tests fine for all cases - specific types and class-wide vars alike. The issue was not just some simple omission. In fact there was not just a single issue - complete implementation required implementing parallel type hierarchies (although with minimum of duplicated code - only for illustration purpose in this case; could be tied up even more, see the comments in the code if anybody is interested by any chance). I essentially ended up reimplementing Ada "standard library", of course in a very simplistic variant, demo-like.  Still, I managed to glue Ada.Containers.Vectors.Vector right over the List_Interface, thus exposing ACV.Vector's primitives directly without extra glue needed. The corresponding code is in the master of:
https://github.com/gerr135/ada_gems/tree/master/list_iface

While digging, I tried alternatives, one of which "hides" the ACV.Vector inside a record - a more classical approach, easier to comprehend (even though the code is mostly the same, less than 10 lines of difference). This code is in "in_rec" branch:
https://github.com/gerr135/ada_gems/tree/in_rec/list_iface


Finally, at some point while testing different things I managed to break gnat, causing it to spill out that gnat Bug message. Relevant code and error message are in yet another branch, here:
https://github.com/gerr135/ada_gems/tree/gnat_bug_01/list_iface

the bug message text is in the "bug_info.txt" file at the top of the list_iface folder..

Is this something already well known or should I report this bug to AdaCore?


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

* Re: class wide iterable (and indexable)
  2019-01-05 18:17               ` George Shapovalov
@ 2019-01-05 20:07                 ` Simon Wright
  2019-01-05 20:41                   ` George Shapovalov
  0 siblings, 1 reply; 76+ messages in thread
From: Simon Wright @ 2019-01-05 20:07 UTC (permalink / raw)


George Shapovalov <gshapovalov@gmail.com> writes:

> Finally, at some point while testing different things I managed to
> break gnat, causing it to spill out that gnat Bug message. Relevant
> code and error message are in yet another branch, here:
> https://github.com/gerr135/ada_gems/tree/gnat_bug_01/list_iface
>
> the bug message text is in the "bug_info.txt" file at the top of the
> list_iface folder..
>
> Is this something already well known or should I report this bug to
> AdaCore?

I think you should submit it. This is an ICE, should be of interest to
AdaCore even if the circumstances are unusual!


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

* Re: class wide iterable (and indexable)
  2019-01-05 17:05             ` Jeffrey R. Carter
@ 2019-01-05 20:18               ` Dmitry A. Kazakov
  2019-01-05 21:09               ` Shark8
  1 sibling, 0 replies; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-05 20:18 UTC (permalink / raw)


On 2019-01-05 18:05, Jeffrey R. Carter wrote:

> A major problem with programming by extension is that it requires 
> violating the S/W-engineering principle of locality.

A principle that would require "+" operations (ARM 4.5.3) (Integer, 
Real, Complex etc) all implemented by the same body? Trilling, but 
evidently absurd.

> S/W engineers don't willingly violate those principles,

Some ignore separation of interface and implementation as "locality" 
would require, but majority, at least of Ada practitioners, I hope do not.

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

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

* Re: class wide iterable (and indexable)
  2019-01-05 20:07                 ` Simon Wright
@ 2019-01-05 20:41                   ` George Shapovalov
  0 siblings, 0 replies; 76+ messages in thread
From: George Shapovalov @ 2019-01-05 20:41 UTC (permalink / raw)


On Saturday, January 5, 2019 at 9:07:10 PM UTC+1, Simon Wright wrote:
> George Shapovalov <gshapovalov@gmail.com> writes:
> > Is this something already well known or should I report this bug to
> > AdaCore?
> I think you should submit it. This is an ICE, should be of interest to
> AdaCore 
Ok, then I'll try to go about submitting it tomorrow (its getting late here today already).

> even if the circumstances are unusual!
Not for me :). This is far from the first gnat bug incidence I observe. One time it was even much weirder - first it started spitting out compilation error messages with clearly misplaced line of code references (off by a few lines, within the block unreachable by the quoted problematic line), and finally gave up and went down with another gnat bug message when pushed a bit more. At the time, IIRC, I was making another attempt to tie different type hierarchies together (and I remember child packages affected gnat stability too, compared to when I tried to pull them all together in one big package instead) while trying to absolutely avoid any code duplication. Similar to what Dmitry was describing here in this thread only instead of heavy generics use I was (ab)using interfaces..
But that was already a few years ago, on a much older gnat version (based around gcc-4 I think) with both FSF and ACT gnat rather in flux at the moment. So I doubt it makes sense at present to try to dig up that code.

So, I'll just submit this bug, as it concerns present gnat version (dev-lang/gnat-2018-r1 based on gcc-7.3.1 backend). 

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

* Re: class wide iterable (and indexable)
  2019-01-05  9:21           ` Randy Brukardt
  2019-01-05 10:07             ` Dmitry A. Kazakov
  2019-01-05 17:05             ` Jeffrey R. Carter
@ 2019-01-05 20:46             ` Shark8
  2019-01-06  9:43               ` Dmitry A. Kazakov
  2 siblings, 1 reply; 76+ messages in thread
From: Shark8 @ 2019-01-05 20:46 UTC (permalink / raw)


On Saturday, January 5, 2019 at 2:21:55 AM UTC-7, Randy Brukardt wrote:
> "Dmitry A. Kazakov" wrote in message 
> ...
> > In real programs dispatch is rare, thus there is no overhead.
> 
> This is probably true, but then interfaces are even more useless (they 
> provide nothing that could possibly be of value other than dispatch!).
> 
> > I don't know which overhead Randy meant, though. Maybe, space overhead? 
> > That is not nearly close to what generics produce in GNAT...
> 
> Dispatching is very expensive for interfaces, in that some form of search is 
> needed. (Note: I have no idea how GNAT implements them exactly.) It might be 
> possible to do some sort of link-time assignment of interface identifiers 
> and link-time tag construction to avoid some of that cost (at the cost of a 
> lot of space), but that would be such a complex and unusual project 
> (conventional linkers don't support anything like that) that I've always 
> considered it impraactical.

There are some optimizations that can be done, these three papers show some interesting methods for resolving/optimizing dynamic-calls:

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.53.1099&rep=rep1&type=pdf
http://web.cs.ucla.edu/~palsberg/tba/papers/dean-grove-chambers-ecoop95.pdf
https://scholarworks.umass.edu/cgi/viewcontent.cgi?article=1008&context=cs_faculty_pubs

IIUC, the techniques also work in the presence of full-multi dispatch.


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

* Re: class wide iterable (and indexable)
  2019-01-05 17:05             ` Jeffrey R. Carter
  2019-01-05 20:18               ` Dmitry A. Kazakov
@ 2019-01-05 21:09               ` Shark8
  2019-01-06 10:11                 ` Jeffrey R. Carter
  1 sibling, 1 reply; 76+ messages in thread
From: Shark8 @ 2019-01-05 21:09 UTC (permalink / raw)


On Saturday, January 5, 2019 at 10:05:50 AM UTC-7, Jeffrey R. Carter wrote:
> 
> A major problem with programming by extension is that it requires violating the 
> S/W-engineering principle of locality. S/W engineers don't willingly violate 
> those principles, so we can conclude that those who like programming by 
> extension are not S/W engineers.

Hm, I'm not sure I agree with you -- plug-ins seem to be a counter-example in that they *are* extensions [of the base program] -- it seems a bit excessive to think that any program that uses/handles plug-ins is ill-designed and by-nature violative of good SW engineering.

Of course this is an interesting observation in its own right, and I should like to hear more.

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

* Re: class wide iterable (and indexable)
  2019-01-04 12:20           ` George Shapovalov
@ 2019-01-05 23:29             ` Jere
  2019-01-05 23:50               ` Jere
  0 siblings, 1 reply; 76+ messages in thread
From: Jere @ 2019-01-05 23:29 UTC (permalink / raw)


On Friday, January 4, 2019 at 7:20:27 AM UTC-5, George Shapovalov wrote:
> <SNIPPED>
> > > Besides linking various type hierarchies together, interfaces are good for containing common code that does not care about specific data storage details.
> > 
> > No, interfaces cannot contain common code except for class-wide one. 
> Yes, I have meant the class-wide methods here of course. Although I must admit I wished more than once that non null/abstract methods that could be inherited and overriden are allowed.  Of course they could only reference other methods (as the data is non-existent at this point), all eventually operating on the abstract/null primitives that are essentially "axioms" of the specific interface. But thus one could provide meaningful abstracted functionality that could be overriden in a sane way, removing the need for  various tricks, one of which you show in your comment. 

You can using a Mixin Generic along with the interface.  Consider the
following example:

*******************************************

with Ada.Text_IO; use Ada.Text_IO;

procedure Hello is

    package Some_Interface is
    
        type The_Interface is limited interface;
        function f1(Self : The_Interface) return Integer is abstract;
        function f2(Self : The_Interface) return Integer is abstract;
        function f3(Self : The_Interface) return Integer is abstract;
        
        generic
            type Base is tagged limited private;
        package Mixin is
            type Derived is new Base and The_Interface with null record;
            overriding function f1(Self : Derived) return Integer;
            overriding function f2(Self : Derived) return Integer;
            overriding function f3(Self : Derived) return Integer;
        end Mixin;
        
    end Some_Interface;
    
    package body Some_Interface is
        package body Mixin is
            function f1(Self : Derived) return Integer is
            begin
                return 10;
            end f1;
            function f2(Self : Derived) return Integer is
            begin
                return 20;
            end f2;
            function f3(Self : Derived) return Integer is
            begin
                return Self.f1 + Self.f2;
            end f3;
        end Mixin;
    end Some_Interface;
    
    -- For examples using existing inheritance trees we need
    -- a base type
    type Third_Party_Base is tagged null record;
    
    package Examples is
    
        use Some_Interface;
    
        type Example_1 is limited new The_Interface with private;
        
        type Example_2 is new Third_Party_Base and The_Interface with private;
        
    private
    
        -----------------------------------------------
        -- Packages
        -----------------------------------------------
        
        -- For situations where you have no regular base class,
        -- this is needed for the Mixin contract
        type Secret_Base is tagged limited null record;
        package Example_1_Pkg is new Mixin(Base => Secret_Base);
        
        -- For situations where you already have a base class, the
        -- instantiation is simpler.
        package Example_2_Pkg is new Mixin(Base => Third_Party_Base);
        
        -- ****NOTE:  You can chain multiple mixins to get defaults for 
        --            various interfaces.  For Example:
        --               package A_Pkg is new A_Mixin(Base => Some_Base);
        --               package B_Pkg is new B_Mixin(Base => A_Pkg.Derived);
        --            This will add both interfaces from A_Mixin and B_Mixin
        --            to the base type.
        
        -----------------------------------------------
        -- Full Type Declarations
        -----------------------------------------------
        
        type Example_1 is limited new Example_1_Pkg.Derived with null record;
        
        type Example_2 is new Example_2_Pkg.Derived with null record;
    
    end Examples;

begin
    Put_Line("Hello, world!");
end Hello;

*******************************************

However, note that the defaults follow the basic Ada rules.  They don't
redispatch unless you specify that (For example in f3 you would do things
like The_Interface'Class(Self).f1 and so on).  So you have to decide what
you want those defaults really do.  Redispatch is fairly dangerous to do
in Ada since it is not the default for inherited programs.  I would 
caution against it unless you have a real need and know what you are doing.


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

* Re: class wide iterable (and indexable)
  2019-01-05 23:29             ` Jere
@ 2019-01-05 23:50               ` Jere
  2019-01-06  9:34                 ` George Shapovalov
  0 siblings, 1 reply; 76+ messages in thread
From: Jere @ 2019-01-05 23:50 UTC (permalink / raw)


On Saturday, January 5, 2019 at 6:29:11 PM UTC-5, Jere wrote:
> On Friday, January 4, 2019 at 7:20:27 AM UTC-5, George Shapovalov wrote:
> > <SNIPPED>
> > > > Besides linking various type hierarchies together, interfaces are good for containing common code that does not care about specific data storage details.
> > > 
> > > No, interfaces cannot contain common code except for class-wide one. 
> > Yes, I have meant the class-wide methods here of course. Although I must admit I wished more than once that non null/abstract methods that could be inherited and overriden are allowed.  Of course they could only reference other methods (as the data is non-existent at this point), all eventually operating on the abstract/null primitives that are essentially "axioms" of the specific interface. But thus one could provide meaningful abstracted functionality that could be overriden in a sane way, removing the need for  various tricks, one of which you show in your comment. 
> 
> You can using a Mixin Generic along with the interface.  Consider the
> following example:
>   <SNIPPED>

And if you don't like the Mixin method, you can do something a bit closer to
composition and Rust's model (though Ada doesn't support traits, so
it has to be emulated by inheriting an interface instead):

*******************************************

with Ada.Text_IO; use Ada.Text_IO;
procedure Hello is

    package Some_Interface is
    
        type The_Interface is limited interface;
        function f1(Self : The_Interface) return Integer is abstract;
        function f2(Self : The_Interface) return Integer is abstract;
        function f3(Self : The_Interface) return Integer is abstract;
        
        type The_Default is new The_Interface with null record;
        overriding function f1(Self : The_Default) return Integer;
        overriding function f2(Self : The_Default) return Integer;
        overriding function f3(Self : The_Default) return Integer;
        
    end Some_Interface;
    
    package body Some_Interface is
        
        function f1(Self : The_Default) return Integer is
        begin
            return 10;
        end f1;
        function f2(Self : The_Default) return Integer is
        begin
            return 20;
        end f2;
        function f3(Self : The_Default) return Integer is
        begin
            return Self.f1 + Self.f2;
        end f3;
        
    end Some_Interface;
    
    -- For examples using existing inheritance trees we need
    -- a base type
    type Third_Party_Base is tagged null record;
    
    package Examples is
    
        use Some_Interface;
    
        type Example_1 is limited new The_Interface with private;
        overriding function f1(Self : Example_1) return Integer;
        overriding function f2(Self : Example_1) return Integer;
        overriding function f3(Self : Example_1) return Integer;
        
        type Example_2 is new Third_Party_Base and The_Interface with private;
        overriding function f1(Self : Example_2) return Integer;
        overriding function f2(Self : Example_2) return Integer;
        overriding function f3(Self : Example_2) return Integer;
        
    private
        
        -----------------------------------------------
        -- Full Type Declarations
        -----------------------------------------------
        
        type Example_1 is limited new The_Interface with record
            The_Interface_Impl : The_Default;
        end record;
        
        type Example_2 is new Third_Party_Base and The_Interface with record
            The_Interface_Impl : The_Default;
        end record;
    
    end Examples;
    
    package body Examples is
        function f1(Self : Example_1) return Integer is (Self.The_Interface_Impl.f1);
        function f2(Self : Example_1) return Integer is (Self.The_Interface_Impl.f2);
        function f3(Self : Example_1) return Integer is (Self.The_Interface_Impl.f3);
        
        function f1(Self : Example_2) return Integer is (Self.The_Interface_Impl.f1);
        function f2(Self : Example_2) return Integer is (Self.The_Interface_Impl.f2);
        function f3(Self : Example_2) return Integer is (Self.The_Interface_Impl.f3);
    end Examples;

begin
    Put_Line("Hello, world!");
end Hello;

*******************************************

This requires more footwork, but enforces that all
implementors of the interface have to specify a body for all
inherited abstract operations.

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

* Re: class wide iterable (and indexable)
  2019-01-05 23:50               ` Jere
@ 2019-01-06  9:34                 ` George Shapovalov
  2019-01-06 10:19                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 76+ messages in thread
From: George Shapovalov @ 2019-01-06  9:34 UTC (permalink / raw)


> > You can using a Mixin Generic along with the interface.  Consider the
> > following example:
> >   <SNIPPED>
> 
> And if you don't like the Mixin method, you can do something a bit closer to
> composition and Rust's model 
Thank you!
Yes, this does the job done (and I believe the 1st one was what Dmitry already have shown above), achieving the effect of in-mixing overridable methods. However allowing interfaces to have non0bull or abstract primitives (obviously referencing onyl existing entities, just like class-wide methods do already anyway) would have been much less cumbersome and much more elegant and readable to begin with..

But this was just a sidenote to that discussion. My original intention was to attempt to move the existing type (that would serve as a top of type hierarchy normally) to the side of a new type tree - which is not that "topologically different" from the mix-in equiliristic, just a bit different way to glue things together. The complicating circumstance in that specific case (which prompted my original post) was to provide indexing/iteration to the entire type tree and then glue Ada.Containers.Vectors right over it, which finally succeeded after more digging through aspects and Ada standard library internals.

Tanks to everybody for informative comments!

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

* Re: class wide iterable (and indexable)
  2019-01-05 20:46             ` Shark8
@ 2019-01-06  9:43               ` Dmitry A. Kazakov
  0 siblings, 0 replies; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-06  9:43 UTC (permalink / raw)


On 2019-01-05 21:46, Shark8 wrote:
> On Saturday, January 5, 2019 at 2:21:55 AM UTC-7, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" wrote in message
>> ...
>>> In real programs dispatch is rare, thus there is no overhead.
>>
>> This is probably true, but then interfaces are even more useless (they
>> provide nothing that could possibly be of value other than dispatch!).
>>
>>> I don't know which overhead Randy meant, though. Maybe, space overhead?
>>> That is not nearly close to what generics produce in GNAT...
>>
>> Dispatching is very expensive for interfaces, in that some form of search is
>> needed. (Note: I have no idea how GNAT implements them exactly.) It might be
>> possible to do some sort of link-time assignment of interface identifiers
>> and link-time tag construction to avoid some of that cost (at the cost of a
>> lot of space), but that would be such a complex and unusual project
>> (conventional linkers don't support anything like that) that I've always
>> considered it impraactical.
> 
> There are some optimizations that can be done, these three papers show some interesting methods for resolving/optimizing dynamic-calls:
> 
> http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.53.1099&rep=rep1&type=pdf
> http://web.cs.ucla.edu/~palsberg/tba/papers/dean-grove-chambers-ecoop95.pdf
> https://scholarworks.umass.edu/cgi/viewcontent.cgi?article=1008&context=cs_faculty_pubs
> 
> IIUC, the techniques also work in the presence of full-multi dispatch.

I skimmed these papers briefly and have an impression that they solve 
problems resolved in Ada 95 long ago.

The problem Randy meant is different. You have a type tag and a 
primitive operation's ID. Out of these two you must get the operation 
body entry point (dispatch).

With single inheritance we can use the tag as a pointer to the array 
indexed by the ID (the dispatch table). The ID can be made dense index 
because all primitive operations are known and added sequentially. You 
simply increment it for each newly declared primitive operation.

With multiple inheritance this does not work anymore for the interfaces. 
When an interface type is declared, you don't know which types will use 
it and thus you cannot assign the IDs to its operations so that they 
will land into unique slots in all dispatching tables of all future 
descendants.

Thus by interfaces you have to use (Tag, ID) in some sort of hash table 
or binary search or whatever, which is less efficient than simple indexing.

A linker could "densify" the IDs later when all dispatching tables are 
settled, but that would also require the dynamic loader to be able to do 
this as well in the case of relocated libraries. Since both lingered in 
the Stone Age under Windows and Linux, that will not happen.

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

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

* Re: class wide iterable (and indexable)
  2019-01-05 21:09               ` Shark8
@ 2019-01-06 10:11                 ` Jeffrey R. Carter
  0 siblings, 0 replies; 76+ messages in thread
From: Jeffrey R. Carter @ 2019-01-06 10:11 UTC (permalink / raw)


On 1/5/19 10:09 PM, Shark8 wrote:
> 
> Hm, I'm not sure I agree with you -- plug-ins seem to be a counter-example in that they *are* extensions [of the base program] -- it seems a bit excessive to think that any program that uses/handles plug-ins is ill-designed and by-nature violative of good SW engineering.

I don't think plug-ins qualify as programming by extension, since they don't 
involve extending an existing type (I'm not very familiar with how plug-ins are 
written for things that allow them, so I may be mistaken).

But I'm not sure that allowing plug-ins is good S/W eng. The goals of S/W eng 
are S/W that is correct, reliable, robust, and easy to understand and modify. 
How do you ensure that if you allow any coder to write a plug-in?

> Of course this is an interesting observation in its own right, and I should like to hear more.

My observations about programming by extension are in the /Ada Letters/ articles 
"Ada's Design Goals and Object-Oriented Programming", "Breaking the Ada Privacy 
Act", and "OOP vs. Readability", available at

http://pragmada.x10hosting.com/papers.html

These are over 20 years old. The 1st and last deal with type extension and the 
2nd with child pkgs that extend their ancestor(s). The type-extension examples I 
cite do not use child pkgs, perhaps because both were new concepts in Ada and 
the authors did not want to confuse readers with an extra new concept, but I 
don't think revising them to use child pkgs would change anything.

-- 
Jeff Carter
"Now look, Col. Batguano, if that really is your name."
Dr. Strangelove
31


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

* Re: class wide iterable (and indexable)
  2019-01-06  9:34                 ` George Shapovalov
@ 2019-01-06 10:19                   ` Dmitry A. Kazakov
  2019-01-06 11:30                     ` George Shapovalov
  0 siblings, 1 reply; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-06 10:19 UTC (permalink / raw)


On 2019-01-06 10:34, George Shapovalov wrote:
> However allowing interfaces to have non0bull or abstract primitives (obviously referencing onyl existing entities, just like class-wide methods do already anyway) would have been much less cumbersome and much more elegant and readable to begin with..

It was and is fiercely opposed all the time!

(I have a conspiracy theory. All is because the keyword "interface" will 
not need to be reserved anymore! (:-))

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


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

* Re: class wide iterable (and indexable)
  2019-01-06 10:19                   ` Dmitry A. Kazakov
@ 2019-01-06 11:30                     ` George Shapovalov
  2019-01-06 12:45                       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 76+ messages in thread
From: George Shapovalov @ 2019-01-06 11:30 UTC (permalink / raw)


On Sunday, January 6, 2019 at 11:19:17 AM UTC+1, Dmitry A. Kazakov wrote:
> It was and is fiercely opposed all the time!
But you and many others agree that its a good idea.
There is that expression, that old theories do not get overturned, rather they die out with their hosts (I think it was first said in Physics, circa 1920-30s, during that Quantum discussion period, but I am now across so many disciplines, I cannot be sure). So, if we just outlive them.. :)

> (I have a conspiracy theory. All is because the keyword "interface" will 
> not need to be reserved anymore! (:-))
How so? Tagged types allow this, and both "type" and "tagged" are reserved words. Besides, if that would be a corner issue, the opposition could be placated by proposing to keep it reserved by some mandate :).

George

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

* Re: class wide iterable (and indexable)
  2019-01-06 11:30                     ` George Shapovalov
@ 2019-01-06 12:45                       ` Dmitry A. Kazakov
  2019-01-06 13:18                         ` George Shapovalov
  0 siblings, 1 reply; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-06 12:45 UTC (permalink / raw)


On 2019-01-06 12:30, George Shapovalov wrote:
> On Sunday, January 6, 2019 at 11:19:17 AM UTC+1, Dmitry A. Kazakov wrote:
>> It was and is fiercely opposed all the time!
> But you and many others agree that its a good idea.

But there are also ones who don't even accept the notion of a set of 
types, programming in terms of, still clutching to bare procedural 
decomposition.

I am happy we have got Ada 95. But maybe all the mess introduced in Ada 
2005, 2012 and yet to come with 202X is the backlash for that short 
period of luck...

> There is that expression, that old theories do not get overturned, rather they die out with their hosts (I think it was first said in Physics, circa 1920-30s, during that Quantum discussion period, but I am now across so many disciplines, I cannot be sure). So, if we just outlive them.. :)

Yep, Max Planck:

"A new scientific truth does not triumph by convincing its opponents and 
making them see the light, but rather because its opponents eventually 
die, and a new generation grows up that is familiar with it."

>> (I have a conspiracy theory. All is because the keyword "interface" will
>> not need to be reserved anymore! (:-))
> How so? Tagged types allow this, and both "type" and "tagged" are reserved words.

Yes. Interface is an abstract tagged type, nothing more except for a 
silly constraint not to provide anything functional.

> Besides, if that would be a corner issue, the opposition could be placated by proposing to keep it reserved by some mandate :).

That is my hope. (:-))

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

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

* Re: class wide iterable (and indexable)
  2019-01-06 12:45                       ` Dmitry A. Kazakov
@ 2019-01-06 13:18                         ` George Shapovalov
  2019-01-06 14:13                           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 76+ messages in thread
From: George Shapovalov @ 2019-01-06 13:18 UTC (permalink / raw)


On Sunday, January 6, 2019 at 1:45:09 PM UTC+1, Dmitry A. Kazakov wrote:
> Yep, Max Planck:
[..]
Ah, yes indeed, thank you for the specifics, it was a while ago that I last had to recall that :).

> Yes. Interface is an abstract tagged type, nothing more except for a 
> silly constraint not to provide anything functional.
Ah, so you mean that if the "stupid nonfunctionality constraint" is removed then there is no need to have an extra reserved word? I see. But there are reasons beyond that. One would be readability and consistence with generally accepted (by now) OOP composition paradigm. Another, and perhaps even more essential is that that non-functionality is two-fold: 
1. provision of inheritable primitives, which is the really lacking feature IMHO (and evidently in opinion of many other people),  and
2. provision of data entries.

The 2nd one, while useful in some situations, can usually be worked around with proper type layout. In fact such prohibition forces to think type layout through up-front often saving much grief later. Moreover, lookup collision resolution rules are very often different for data and methods, quickly causing mess of things. So I think, at least on this one there is a good reason to keep it as is. As such, reserved word "interface" would stand for an abstract type without actual data but with inheritable primitives. Not only this would satisfy many (more) opponents, but it would provide a more complete set coverage of "problem decomposition scenarios"..

George


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

* Re: class wide iterable (and indexable)
  2019-01-06 13:18                         ` George Shapovalov
@ 2019-01-06 14:13                           ` Dmitry A. Kazakov
  2019-01-06 16:33                             ` George Shapovalov
  0 siblings, 1 reply; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-06 14:13 UTC (permalink / raw)


On 2019-01-06 14:18, George Shapovalov wrote:
> On Sunday, January 6, 2019 at 1:45:09 PM UTC+1, Dmitry A. Kazakov wrote:
>> Yep, Max Planck:
> [..]
> Ah, yes indeed, thank you for the specifics, it was a while ago that I last had to recall that :).
> 
>> Yes. Interface is an abstract tagged type, nothing more except for a
>> silly constraint not to provide anything functional.
> Ah, so you mean that if the "stupid nonfunctionality constraint" is removed then there is no need to have an extra reserved word? I see. But there are reasons beyond that. One would be readability and consistence with generally accepted (by now) OOP composition paradigm. Another, and perhaps even more essential is that that non-functionality is two-fold:
> 1. provision of inheritable primitives, which is the really lacking feature IMHO (and evidently in opinion of many other people),  and
> 2. provision of data entries.
3. Constraints. Interfaces cannot have discriminants.

> The 2nd one, while useful in some situations, can usually be worked around with proper type layout. In fact such prohibition forces to think type layout through up-front often saving much grief later. Moreover, lookup collision resolution rules are very often different for data and methods, quickly causing mess of things. So I think, at least on this one there is a good reason to keep it as is. As such, reserved word "interface" would stand for an abstract type without actual data but with inheritable primitives. Not only this would satisfy many (more) opponents, but it would provide a more complete set coverage of "problem decomposition scenarios"..

There is no difference between operations and record members except than 
language design faults/artifacts. Publicly visible record members should 
have been overridable as other operations are. Same applies to the 
attributes.

(This could not be done in Ada 83, which is the only excuse)

Any problem with visibility equally applies to both.

Note also that any so small problem becomes a nightmare when generics 
come into play. A honest macro does not have any of this because it 
simply expands whatever garbage into the source. Ada 83 tried to make 
generic expansions a more safe and this, generates mountains of problems 
in each language corner. Basically, this is a fine reason to reject 
whatever language change - oh, dear, what if this appears in a generic?..

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

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

* Re: class wide iterable (and indexable)
  2019-01-06 14:13                           ` Dmitry A. Kazakov
@ 2019-01-06 16:33                             ` George Shapovalov
  2019-01-06 18:29                               ` George Shapovalov
  2019-01-06 20:18                               ` Dmitry A. Kazakov
  0 siblings, 2 replies; 76+ messages in thread
From: George Shapovalov @ 2019-01-06 16:33 UTC (permalink / raw)


On Sunday, January 6, 2019 at 3:13:45 PM UTC+1, Dmitry A. Kazakov wrote:
> 3. Constraints. Interfaces cannot have discriminants.
Well, discriminants (at their basis) are essentially glorified record members treated in a special way, so I grouped them together with 2. But that special treatment can quickly become "sufficiently special" to warrant a separate category. Especially when we start considering all special-cased derived tagged/untagged types overriding or hiding discriminants, so that it turns "simple parameters of the type" into a mixture of data and code (at least according to some discussions of gnat internals I read at some point)..

 
> There is no difference between operations and record members except than 
> language design faults/artifacts. Publicly visible record members should 
> have been overridable as other operations are. 
From purely logical point of view, perhaps. But once we start considering implementation details, there is a very clear distinction between code and data. Code, you only (usually) have one copy that can be called many times as needed. Data entries can and are duplicated. (At least according to classical paradigm, which is no longer true of course, but see just below).

Overriding method (from this point of view) is trivial - so what that we got some extra block of code which is called perhaps once? But what do we do with overridden record entry? Do we eliminate it? But then what if some grand-grand-child decides to cast some ancestor access to reach out to now hidden entry? Do we keep them around? What, in all millions or billions copies of our records in the running system? Do we make a monstrous compiler that would require a cluster of Blue Genes to figure out the specifics and only keep data records individually as needed? But then, what if this is a dynamically running (indeed large) system only parts of which can be "rebooted" but it cannot be taken down as a whole? So I'd say it does make sense to make this distinction (between code and data, even logically) if we want to have a practically sensible compiler, code for which we can any hope ourselves to comprehend..

And now, of course, we come back to generics, or rather their "abuse, beyond initial intention". Having powerful and type-checked generics is a big plus of Ada, except when we use that mechanism to blend the boundaries between "code" and "data" by creating millions of specialized code copies thus ending up with "callable data". You refer to just such a situation being common in your projects and I feel your pain. This is also exactly the reason why I try to avoid such scenario as much as possible - going as far as breaking compiler while (ab)using interfaces (compared to what is expected in Ada, although it is a normal use case in some other languages) but to avoid overusing generics beyond their "original intention".
And so, we have come a full circle in this discussion, leading again to this:

> Note also that any so small problem becomes a nightmare when generics 
> come into play. A honest macro does not have any of this because it 
> simply expands whatever garbage into the source. 
Indeed, exactly in view of all above (both sets of quotes). But it (honest macro) is also more limited and often leads to completely unintended consequences, because ones logical intention rarely maps exactly onto lexical representation in a code snippet..

Well, what can be said about this? Complex systems are complex. And "for every problem there exists a solution that is clear, simple and wrong". I don't think we can have a rainbow unicorn that would make everything magically simple[*]. But we can, at least, strive to keep our tools sane/verifiable in order to guard our own sanity :). Even a very simplistic tool can always be abused. Therefore I think it it more important to provide a clear base/most common case use pattern. This will provide more safeguarding by decreasing desire to abuse than a strong but convoluted attempt to prohibit unintended use. People will always find a way.
That was an attempt to get back to the subject of multiple inheritance and unintended consequences of prohibiting useful applications of its basic features :).

[*] Except that may be we can, in the form of "true AI". If such thing is indeed possible[**], it may also be that it can generate "magic" (from our point of view, because we will not understand them) solutions that appear simple in action. Only that would make us also irrelevant and it would be more likely to concentrate itself on its own problems, rather than ours. Unless we involve ourselves deeply in its upbringing to the point of blending in and becoming a part of it.. But that is an entirely different philosophical topic :)

[**] And the premise of its possibility is based on observation that systems that we perceive as alive and intelligent (e.g., ourselves) are essentially complex biophysical systems based around a fixed set of laws. So far the latest set of laws, as we could formulate them, stood up unviolated for over 70 years. But the underlying systems, even "simple" eucariotic cells, are indeed very complex, easily beyond the level of our "biggest systems" - as a practicing Biology/Biophysics Prof. involved in both experiments and simulations I can attest to that first hand. As well as to a funny observation that vast majority of "proper biologists" are already hopelessly lost in anything beyond their very specific and small project :). 

But I digress, this went completely off the rails at this point, so  I better stop here..

George

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

* Re: class wide iterable (and indexable)
  2019-01-06 16:33                             ` George Shapovalov
@ 2019-01-06 18:29                               ` George Shapovalov
  2019-01-06 20:32                                 ` Dmitry A. Kazakov
  2019-01-06 20:18                               ` Dmitry A. Kazakov
  1 sibling, 1 reply; 76+ messages in thread
From: George Shapovalov @ 2019-01-06 18:29 UTC (permalink / raw)


> [*] Except that may be we can,
I guess I better clarify those last parts (especially the [*] and [**]).

My point is that some (and increasingly more) problems are intrinsically complex. And our comprehension capacity is limited [*]. Short of developing a "higher intelligence entity" or (even better) becoming one (I mean here beyond natural selection progression which, at fixed traits accumulation rate measured in centuries and the need for periodic ecosystem crises to force selection, is too slow to cope with present information inflation), we cannot significantly affect the balance between increasing complexity of the tasks we face and our development capacity. Thus the need for sane and well designed tools and, perhaps, faster standard review process. But I suspect this last suggestion will cause even more grief than all other technical ones :) (nor is it realistic in present situation).


[*] I would even go as far as claiming that we are already approaching upper limit learning capacity of an unmodded brain. With people "at the top" spending over 50% of their life daily concentrating on some specific topic to reach "significant" level already, we can expect increase of maybe few more times in efficiency, but hardly an order of magnitude or more. Besides, a lot of the recent increase (past few decades) came from information availability. But at this point we already seem to be bottlenecked by our individual ability to process this information. Thus the proliferation of all these recent popular services of "suggestive info preprocessing" initiated by Google, but rather ubiquitous by now. Mostly targeted at masses at the moment, but more useful and specialized services being developed too (and rather essential in order to just stay on top of all the developments in any given domain). But I would like to see it taken to yet another level, with a more effective exchange protocols, going beyond mere verbal communication. This is however is yet ways off, as it depends on installing another common layer of direct-to-brain data exchange first and standardizing it (with a huge potential for abuse of course).
But now this is getting deep into bioengeneering, way away from the original subject or even this group focus..


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

* Re: class wide iterable (and indexable)
  2019-01-06 16:33                             ` George Shapovalov
  2019-01-06 18:29                               ` George Shapovalov
@ 2019-01-06 20:18                               ` Dmitry A. Kazakov
  2019-01-06 21:58                                 ` George Shapovalov
  1 sibling, 1 reply; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-06 20:18 UTC (permalink / raw)


On 2019-01-06 17:33, George Shapovalov wrote:
> On Sunday, January 6, 2019 at 3:13:45 PM UTC+1, Dmitry A. Kazakov wrote:
>> 3. Constraints. Interfaces cannot have discriminants.
> Well, discriminants (at their basis) are essentially glorified record members treated in a special way, so I grouped them together with 2. But that special treatment can quickly become "sufficiently special" to warrant a separate category. Especially when we start considering all special-cased derived tagged/untagged types overriding or hiding discriminants, so that it turns "simple parameters of the type" into a mixture of data and code (at least according to some discussions of gnat internals I read at some point)..

This is largely because discriminants fuse two different things: 
constraint and a record member representing the constraint. Not every 
constraint is a record member, e.g. array bounds. So the idea is flawed.

>> There is no difference between operations and record members except than
>> language design faults/artifacts. Publicly visible record members should
>> have been overridable as other operations are.
>  From purely logical point of view, perhaps. But once we start considering implementation details, there is a very clear distinction between code and data. Code, you only (usually) have one copy that can be called many times as needed. Data entries can and are duplicated. (At least according to classical paradigm, which is no longer true of course, but see just below).

Both record member and code should be mere implementations of the 
interface <object>.<name>. Things you refer are implementation aspects 
nothing more. The problems arise because of entangled interface and 
implementation.

> Overriding method (from this point of view) is trivial - so what that we got some extra block of code which is called perhaps once? But what do we do with overridden record entry? Do we eliminate it?

You override getter and/or setter. Whatever representation of inherited 
bases stay unless overridden as a whole. The similar approach is used 
for discriminants: either extension or overhaul. (The latter case may 
not be limited, it must be strictly by-value)

> And now, of course, we come back to generics, or rather their "abuse, beyond initial intention". Having powerful and type-checked generics is a big plus of Ada, except when we use that mechanism to blend the boundaries between "code" and "data" by creating millions of specialized code copies thus ending up with "callable data". You refer to just such a situation being common in your projects and I feel your pain. This is also exactly the reason why I try to avoid such scenario as much as possible - going as far as breaking compiler while (ab)using interfaces (compared to what is expected in Ada, although it is a normal use case in some other languages) but to avoid overusing generics beyond their "original intention".

True, but the lobby behind generics is quite powerful. So many things 
unavailable for the core language were crammed into generics. For 
example, Ada 83 had no subroutine type parameters. Even now it is only a 
pointer to subprograms you can have, though lots of accessibility 
problems would go if you could pass a subprogram instead of a pointer 
to. But generics had subroutine parameters from the day one!

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


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

* Re: class wide iterable (and indexable)
  2019-01-06 18:29                               ` George Shapovalov
@ 2019-01-06 20:32                                 ` Dmitry A. Kazakov
  2019-01-06 21:47                                   ` George Shapovalov
  0 siblings, 1 reply; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-06 20:32 UTC (permalink / raw)


On 2019-01-06 19:29, George Shapovalov wrote:
>> [*] Except that may be we can,
> I guess I better clarify those last parts (especially the [*] and [**]).
> 
> My point is that some (and increasingly more) problems are intrinsically complex. And our comprehension capacity is limited [*]. Short of developing a "higher intelligence entity" or (even better) becoming one (I mean here beyond natural selection progression which, at fixed traits accumulation rate measured in centuries and the need for periodic ecosystem crises to force selection, is too slow to cope with present information inflation), we cannot significantly affect the balance between increasing complexity of the tasks we face and our development capacity. Thus the need for sane and well designed tools and, perhaps, faster standard review process. But I suspect this last suggestion will cause even more grief than all other technical ones :) (nor is it realistic in present situation).

Software developing tools add and multiply complexity. Each tool is an 
indicator of some or someone's defeat.

> [*] I would even go as far as claiming that we are already approaching upper limit learning capacity of an unmodded brain. With people "at the top" spending over 50% of their life daily concentrating on some specific topic to reach "significant" level already, we can expect increase of maybe few more times in efficiency, but hardly an order of magnitude or more. Besides, a lot of the recent increase (past few decades) came from information availability. But at this point we already seem to be bottlenecked by our individual ability to process this information.

That depends on the structure of the information. The amount of 
information required to solve the same task in Assembler and in Ada is 
quite different.

> Thus the proliferation of all these recent popular services of "suggestive info preprocessing" initiated by Google, but rather ubiquitous by now. Mostly targeted at masses at the moment, but more useful and specialized services being developed too (and rather essential in order to just stay on top of all the developments in any given domain).

This is well advertised snake oil. Most of the software is. We sell 
people solutions for non-existent problems in order to create new, even 
more imaginary, problems, for which we will sell solutions too...

> But I would like to see it taken to yet another level, with a more effective exchange protocols, going beyond mere verbal communication. This is however is yet ways off, as it depends on installing another common layer of direct-to-brain data exchange first and standardizing it (with a huge potential for abuse of course).

Not in the near future. So far we know basically nothing about our 
brain. It is like taking IR images of the motherboard while compiling 
Ada program...

> But now this is getting deep into bioengeneering, way away from the original subject or even this group focus..

Eugenics, you mean... (:-))

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

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

* Re: class wide iterable (and indexable)
  2019-01-06 20:32                                 ` Dmitry A. Kazakov
@ 2019-01-06 21:47                                   ` George Shapovalov
  2019-01-07  9:37                                     ` Niklas Holsti
  0 siblings, 1 reply; 76+ messages in thread
From: George Shapovalov @ 2019-01-06 21:47 UTC (permalink / raw)


Ditto on the generics and core language limitations. This thread came out exactly out of trying to reimplement something that should have been there to begin with..

On Sunday, January 6, 2019 at 9:32:07 PM UTC+1, Dmitry A. Kazakov wrote:
> > Thus the proliferation of all these recent popular services of 
[..]
> This is well advertised snake oil. Most of the software is. We sell 
> people solutions for non-existent problems in order to create new, even 
> more imaginary, problems, for which we will sell solutions too...
Yes and no. 
Mostly yes for selling snake oil to mass market. However some of these tools may be extremely useful. For example an effective literature mining tool that could "pre-digest" en-mass searches indivisualized to a specific individual/project. Not merely a collection of a keywords with links (what most of the "services" I tried provide as of now), but going beyond that. I would appreciate such a tool a lot. The reality of modern science is that even to stay up to day with on a single topic can easily take a significant amount of time, even with spending only a few min per (more essential) paper. And I tend to have rather wide interests.. Fortunately this issue may be fixable in near future, as there is some development in this area. Recently I had a chat with some startup developers orienting on Bio field, with the goal to provide a tool (of course a popular now term AI was used more than once) to help biotech/pharma companies (who are normally chronically behind on "proper science" and comprehension of mechanisms they are supposed to study, but who have a lot of money). They had an interesting idea that could actually be workable. Only they were too optimistic IMO about its "hands-off" work perspectives. When I expressed my concerns and usual point that tools addressing complex problems typically have complicated interface to deal with all the necessary details, the response was - "oh, it will totally work, and that's the beauty of this visualization approach", but they yet had that common situation "over a year in production and already trying to get sales but no finished product yet, we have to train people to be our end points dealing with customers" - quite telling :).
But to someone who has a sense of the subject in general and reasonable experience with non-trivial tools, such a system could be very useful. The main issue is the usual dumbing down for mass user which, more often than not, throws the baby out with the water..


> > But I would like to see it taken to yet another level, with a more effective exchange protocols, going beyond mere verbal communication. This is however is yet ways off, as it depends on installing another common layer of direct-to-brain data exchange first and standardizing it (with a huge potential for abuse of course).
> 
> Not in the near future. So far we know basically nothing about our 
> brain. It is like taking IR images of the motherboard while compiling 
> Ada program...
You would be amazed about what is going on in some labs :). And "knowing basically nothing" does not stop people. But that was exactly my point - we can already do amazing things which we do not fully understand or control. Usually there is a general, sufficiently clear idea which gets tested on a simple system. Then to make it workable people scale up the hard/wet-ware side and go talk to bioinformaticians to get some software to deal with the data. In some cases this actually gets off the ground on a more complex use cases and start working without either side having a good understanding of exactly what is going on. CS people have no real idea of biology behind, and biologists are totally blank on the complexity of the software that is trying to hold things together. And none of them have even a slightest idea about physical processes underlying this, and in many cases those are also important. But in the current scientific environment - "publish positive or perish" - nobody cares as long as there is some result that can be passed off as "hey, it worked!". But sometimes it does work and does something nontrivial :). Although true cross-discipline is sadly very rare, but then there simply not that many people who can handle it. And you would need at least one person sufficiently fluid in Biotech, physics/engeneering and software to keep it all in perspective..

Of course the ultimate goal I stated above is ways off, but I do have an idea how that could be achieved :).But that's not a "simple idea", it does require a gradual testing of multiple layers, finally finishing the neural/computer interfacing is one of them (work on that has been going on, here and there, for over 15 years already with some things quite workable, but no (at least in the open) systemic push to get it finished and tested properly). Contyrol of invasive properties of the cells is also underway for quite some years. But most of the research is concentrated on specific tissues/diseases with people mostly happy with just receiving the next tranche of grant money, then publishing, then doing it all over again with a small tweak to what has just been done. But that's academia for you, doing a grossly different ambitious thing is counter to well-being in that environment :).


> > But now this is getting deep into bioengeneering, way away from the original subject or even this group focus..
> 
> Eugenics, you mean... (:-))
Nope, honest bioengeneering - coupling hard-, soft- and wet-ware together ;). If only I could find some company with enough resources and truly interested (I can think of many applications, from biotics, prosthetics to military). I have been getting that feeling for a year or two already, that this is becoming feasible and now is the time to start..

George

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

* Re: class wide iterable (and indexable)
  2019-01-06 20:18                               ` Dmitry A. Kazakov
@ 2019-01-06 21:58                                 ` George Shapovalov
  2019-01-07  8:28                                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 76+ messages in thread
From: George Shapovalov @ 2019-01-06 21:58 UTC (permalink / raw)


Just on a small specifics here.

On Sunday, January 6, 2019 at 9:18:09 PM UTC+1, Dmitry A. Kazakov wrote:
> You override getter and/or setter. Whatever representation of inherited 
> bases stay unless overridden as a whole. The similar approach is used 
> for discriminants: either extension or overhaul. (The latter case may 
> not be limited, it must be strictly by-value)
So, out of 3 variants, you select the first one - to keep all things around and accumulate as you go, which *is* the safest, and probably the most sensible, way to do it. But this will not fly universally - what about situations where you have billions of copies of your record (all with different data). Wasting even small amounts per entry (and as stuff accumulates over years, that waste may become the majority of space taken) is a big no-no for some scenarios. So, for a "universal language" you must have a provision of data layout control (which Ada has) extended to such situations. Which means a more complex field handling. Which, in turn, leads either to exposing this to developers, thus augmenting abuse and insanity, or a really tricky and complex "garbage collection" working on dynamic type hierarchies. I am afraid there is no easy solution to that. And that compromise of treating "data" and "code" separately seems an acceptable tradeoff (even if yes, mathematically, it is possible to handle them in a universal way)..

But then it is true, with discriminants it is already violated. So I guess treating data the same way is the next natural step. Oh well, most developers will either be too scared to use that or will do nonsemsical things without proper understanding, leading to failed software and more possibilities for the rest of us to do things properly :).


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

* Re: class wide iterable (and indexable)
  2019-01-06 21:58                                 ` George Shapovalov
@ 2019-01-07  8:28                                   ` Dmitry A. Kazakov
  0 siblings, 0 replies; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-07  8:28 UTC (permalink / raw)


On 2019-01-06 22:58, George Shapovalov wrote:
> Just on a small specifics here.
> 
> On Sunday, January 6, 2019 at 9:18:09 PM UTC+1, Dmitry A. Kazakov wrote:
>> You override getter and/or setter. Whatever representation of inherited
>> bases stay unless overridden as a whole. The similar approach is used
>> for discriminants: either extension or overhaul. (The latter case may
>> not be limited, it must be strictly by-value)
> So, out of 3 variants, you select the first one - to keep all things around and accumulate as you go, which *is* the safest, and probably the most sensible, way to do it. But this will not fly universally - what about situations where you have billions of copies of your record (all with different data).

It is substitutability. In by-reference case you must keep the 
representation, no way around it. Thus, extension is the only way. This 
is the model used by Ada tagged types.

In the by-value case you can replace the representation, but reconstruct 
it back when you substitute.

There is no third option, except for making code adjustments according 
to the actual types. This is how class-wide operation work already.

And there is no deep hierarchies, so billions of copies would be a great 
exaggeration.

> Oh well, most developers will either be too scared to use that or will do nonsemsical things without proper understanding, leading to failed software and more possibilities for the rest of us to do things properly :).

Software fails when developers strive to understand things they need not 
to while paying no attention to ones they must.

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

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

* Re: class wide iterable (and indexable)
  2019-01-06 21:47                                   ` George Shapovalov
@ 2019-01-07  9:37                                     ` Niklas Holsti
  2019-01-07 16:24                                       ` George Shapovalov
  0 siblings, 1 reply; 76+ messages in thread
From: Niklas Holsti @ 2019-01-07  9:37 UTC (permalink / raw)


On 19-01-06 23:47 , George Shapovalov wrote:

>>> ...  it depends on
>>> installing another common layer of direct-to-brain data exchange
>>> first and standardizing it (with a huge potential for abuse of
>>> course).
> If only I could find some company with enough resources
> and truly interested (I can think of many applications, from biotics,
> prosthetics to military). I have been getting that feeling for a year
> or two already, that this is becoming feasible and now is the time to
> start..

Have you looked at Neuralink?

https://neuralink.com/

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

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

* Re: class wide iterable (and indexable)
  2019-01-07  9:37                                     ` Niklas Holsti
@ 2019-01-07 16:24                                       ` George Shapovalov
  0 siblings, 0 replies; 76+ messages in thread
From: George Shapovalov @ 2019-01-07 16:24 UTC (permalink / raw)


On Monday, January 7, 2019 at 10:37:56 AM UTC+1, Niklas Holsti wrote:
> Have you looked at Neuralink?
> 
> https://neuralink.com/

Wow, that one actually looks right on point! Thank you.
For some (personal/business) reasons I am looking very intently at Canada now, but this one looks definitely interesting. Too close on-point to pass up.
Thanks.

George

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

* Re: class wide iterable (and indexable)
  2019-01-05 10:07             ` Dmitry A. Kazakov
  2019-01-05 18:17               ` George Shapovalov
@ 2019-01-07 21:07               ` Randy Brukardt
  2019-01-08  9:51                 ` Dmitry A. Kazakov
  2019-01-08 18:32                 ` G. B.
  1 sibling, 2 replies; 76+ messages in thread
From: Randy Brukardt @ 2019-01-07 21:07 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:q0pvlp$1vp1$1@gioia.aioe.org...
> On 2019-01-05 10:21, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:q0n6av$1tqs$1@gioia.aioe.org...
>> ...
>>> In real programs dispatch is rare, thus there is no overhead.
>>
>> This is probably true, but then interfaces are even more useless (they
>> provide nothing that could possibly be of value other than dispatch!).
>
> From the SW design POV they provide a description of an interface, which 
> is a lot of value as is.

That's primarily the job of package specifications, how the contents are 
structured isn't very relevant from a description standpoint.

...
>> ...
>>> No, interfaces cannot contain common code except for class-wide one. Is
>>> that what Randy meant about overhead?
>>
>> Not really. My main point is that you'll never have more than one 
>> concrete
>> instance of a generic interface in any individual program (certainly not 
>> of
>> an interface like that of a container),
>
> I don't understand this. Usually I have dozens of instantiations of the 
> same generics with different actual parameters.

Right, but all of those are *different* interfaces because they have 
*different* generic parameters. You can't mix those types in any useful way, 
because you almost always have the generic parameter type(s) involved.

For instance, for the containers, an interface would have to contain the 
element type. But that substantially limits reuse, because almost every 
container instance would have a different element type. You can't even pass 
just the interface into a generic because you wouldn't be able to call the 
primitives without knowing the element type. To make such a reuse possible 
you'd have to pass so many parameters that you are typing instantiations for 
days. And then the compilation time also would be days. You'd have to be 
slightly mad to even try it. :-)

>> Note: I mean one concrete type, there might be many objects of that type.
>> But it doesn't make sense to use bounded and indefinite containers at the
>> same time for the same element type.
>
> Of course it does. The best example is Ada strings, a container of 
> characters. Practically every program in effect uses both bounded and 
> unbounded strings, the later, maybe, in the form of access String (I tend 
> to avoid Unbounded_String).

As with many things OOP, there seems to be exactly one example where it 
works. And everything else it doesn't work (or at least help - it "works" in 
the sense that you can write it that way and get it to work -- but you've 
gained nothing, you've just changed the problems).

>> Dmitry is of course an all-interface all the time sort of guy. All I see
>> from that is a vast amount of typing to get nothing in particular in 
>> return.
>
> You get type safety. Otherwise you can always go back K&R C! (:-))

Ada has plenty of type safety without using OOP.

>> [But I'm not much of a fan of OOP, either; the big advantage of OOP is
>> requiring few recompiles when adding features. That was a big deal in 
>> 1990,
>> but it hardly matters today. (I can recompile the entirety of Janus/Ada -
>> 250,000 lines - in 15 minutes or so. Why try to save compiles?) And for
>> that, you get to type dozens and dozens of declarations to do anything.
>
> That is because compilers are no longer large software, not even 
> medium-size (:-)). My current project takes a half of week to recompile 
> from scratch [*].

Because you greatly overuse generics in the hopes of making interfaces 
useful. [You admitted as much at the bottom of this message.] You understand 
the cost of using interfaces very well, yet don't seem to make the obvious 
connection. ;-)

> And recompilation is not the biggest problem. Deployment of the modules 
> is.

Keeping protocols consistent is definitely a hard problem. (One I'm glad to 
skip.) I don't see any reason that OOP would help there, though. My attempt 
at that in the Claw Builder was mostly unsuccessful.

 >> While the supposedly terrible case statement solution gives you case
>> completeness checks, variant checks, and essentially has no more chance 
>> of
>> failure (and costs a lot less, and keeps all of the similar code together
>> rather that scattering it about to every different kind of object).
>
> The main problem is that the "similar" code logically has nothing in 
> common, except the shared interface. It must be written by different 
> teams, at different locations and time. Independently tested, used, 
> deployed, versioned, maintained. The case-statement solution crushes not 
> only the architecture but all software process.

Understood, but I'm a "smaller is better" guy. If the team for the project 
doesn't fit in a room, you are guaranteed to have to mess. You can only get 
by then with very strong specifications -- but interfaces themselves don't 
buy anything there (the reverse, in fact, since they're hard to serialize). 
The specifications have to include not just declarations and semantics but 
data layout and protocols and all of that mess that never really works.

And you talk about this a lot, so I don't know what it is that you think you 
gain with interfaces that you wouldn't have with a normal record type and 
primitive operations.

> ----------------------
> * GNAT is awfully slow when compiling specifically generic instantiations, 
> and I have lots of them. The more I have, the more I hate them.

This is the point where I'd usually suggest trying a different compiler. :-) 
A compiler using shared generics could take a lot less time to compile 
instances because there is little code involved. OTOH, I don't want you to 
try Janus/Ada (even on the code that don't use actual interfaces), 'cause 
the way you use generics would inevitably break stuff and I'd hate to have 
to debug code like that. :-) :-)

                              Randy.


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

* Re: class wide iterable (and indexable)
  2019-01-07 21:07               ` Randy Brukardt
@ 2019-01-08  9:51                 ` Dmitry A. Kazakov
  2019-01-08 19:25                   ` Björn Lundin
  2019-01-08 23:26                   ` Randy Brukardt
  2019-01-08 18:32                 ` G. B.
  1 sibling, 2 replies; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-08  9:51 UTC (permalink / raw)


On 2019-01-07 22:07, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:q0pvlp$1vp1$1@gioia.aioe.org...
>> On 2019-01-05 10:21, Randy Brukardt wrote:
>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>>> news:q0n6av$1tqs$1@gioia.aioe.org...
>>> ...
>>>> In real programs dispatch is rare, thus there is no overhead.
>>>
>>> This is probably true, but then interfaces are even more useless (they
>>> provide nothing that could possibly be of value other than dispatch!).
>>
>>  From the SW design POV they provide a description of an interface, which
>> is a lot of value as is.
> 
> That's primarily the job of package specifications, how the contents are
> structured isn't very relevant from a description standpoint.

Package specification is only a container for. How do you know that a 
type is numeric? The choice is between structural and named equivalence. 
With interfaces you can declare it numeric by merely stating that it 
belongs to the class. Without them you need to analyze all declarations 
related to the type in order to guess and there no guaranty that the 
guess is right.

>>>> No, interfaces cannot contain common code except for class-wide one. Is
>>>> that what Randy meant about overhead?
>>>
>>> Not really. My main point is that you'll never have more than one concrete
>>> instance of a generic interface in any individual program (certainly not
>>> of an interface like that of a container),
>>
>> I don't understand this. Usually I have dozens of instantiations of the
>> same generics with different actual parameters.
> 
> Right, but all of those are *different* interfaces because they have
> *different* generic parameters. You can't mix those types in any useful way,
> because you almost always have the generic parameter type(s) involved.

Of course I can mix them. Generics are mixed by passing to other generics:

    generic
       with package X is new P (<>);
    package Mixer is ...

The body is valid for all instances of P. And we still have not 
specialization of generics. So the set of instances cannot be 
constrained later.

Though, I don't see how it is important to mix or not to mix instances 
to the question which method of building a class is better. Tagged 
classes are infinitely better than generic classes.

> For instance, for the containers, an interface would have to contain the
> element type. But that substantially limits reuse, because almost every
> container instance would have a different element type. You can't even pass
> just the interface into a generic because you wouldn't be able to call the
> primitives without knowing the element type. To make such a reuse possible
> you'd have to pass so many parameters that you are typing instantiations for
> days. And then the compilation time also would be days. You'd have to be
> slightly mad to even try it. :-)

I don't see your point. You argue that generic-based design of 
containers is bad. Of course it is bad.

>>> Note: I mean one concrete type, there might be many objects of that type.
>>> But it doesn't make sense to use bounded and indefinite containers at the
>>> same time for the same element type.
>>
>> Of course it does. The best example is Ada strings, a container of
>> characters. Practically every program in effect uses both bounded and
>> unbounded strings, the later, maybe, in the form of access String (I tend
>> to avoid Unbounded_String).
> 
> As with many things OOP, there seems to be exactly one example where it
> works. And everything else it doesn't work (or at least help - it "works" in
> the sense that you can write it that way and get it to work -- but you've
> gained nothing, you've just changed the problems).

At least there is one. Generics have none.

>>> Dmitry is of course an all-interface all the time sort of guy. All I see
>>> from that is a vast amount of typing to get nothing in particular in
>>> return.
>>
>> You get type safety. Otherwise you can always go back K&R C! (:-))
> 
> Ada has plenty of type safety without using OOP.

No, Ada is all OOP as we do

    type I is new Natural; -- Interface

instead of

    type I is private; -- Nobody knows what
    function "+" (Left, Right : I) return I;
    function "-" (Left, Right : I) return I;
    function "*" (Left, Right : I) return I;
    function "/" (Left, Right : I) return I;
    function "0" return I;
    function "1" return I;
    function "2" return I;
    ...

>>> [But I'm not much of a fan of OOP, either; the big advantage of OOP is
>>> requiring few recompiles when adding features. That was a big deal in
>>> 1990,
>>> but it hardly matters today. (I can recompile the entirety of Janus/Ada -
>>> 250,000 lines - in 15 minutes or so. Why try to save compiles?) And for
>>> that, you get to type dozens and dozens of declarations to do anything.
>>
>> That is because compilers are no longer large software, not even
>> medium-size (:-)). My current project takes a half of week to recompile
>> from scratch [*].
> 
> Because you greatly overuse generics in the hopes of making interfaces
> useful. [You admitted as much at the bottom of this message.] You understand
> the cost of using interfaces very well, yet don't seem to make the obvious
> connection. ;-)

There is no other way to reuse across a set of types. Either generics 
(AKA static polymorphism) or inheritance (AKA dynamic polymorphism).

>> And recompilation is not the biggest problem. Deployment of the modules
>> is.
> 
> Keeping protocols consistent is definitely a hard problem. (One I'm glad to
> skip.) I don't see any reason that OOP would help there, though. My attempt
> at that in the Claw Builder was mostly unsuccessful.

With interfaces you can detect client side problems at compile time. 
Without them you don't know until you actually use a given operation. 
This is the case with generics especially because Ada generics have weak 
contracts.

> And you talk about this a lot, so I don't know what it is that you think you
> gain with interfaces that you wouldn't have with a normal record type and
> primitive operations.

Give me tagged types to freely inherit from and I promise to never use 
interfaces [*] again! (:-))

>> ----------------------
>> * GNAT is awfully slow when compiling specifically generic instantiations,
>> and I have lots of them. The more I have, the more I hate them.
> 
> This is the point where I'd usually suggest trying a different compiler. :-)

And I usually point out that without Linux/VxWorks support and targets 
like ARM there is no chance.

> A compiler using shared generics could take a lot less time to compile
> instances because there is little code involved.

Without any doubt. Worse that that, yes, instances are slow to compile, 
but I have an impression that merely with-ing compiled instances 
drastically increases the compile time of a package and the memory used 
by the compiler. At the end of the dependency chain it becomes minutes 
to compile a three-liner body. There is something utterly wrong with 
GNAT there.

> OTOH, I don't want you to
> try Janus/Ada (even on the code that don't use actual interfaces), 'cause
> the way you use generics would inevitably break stuff and I'd hate to have
> to debug code like that. :-) :-)

I would gladly use Janus/Ada or ObjectAda if I could. I was a happy user 
of the latter long ago. Unfortunately cross-platformity is a requirement 
in these days.
--------------------
* Here, interface = crippled abstract tagged type.

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

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

* Re: class wide iterable (and indexable)
  2019-01-07 21:07               ` Randy Brukardt
  2019-01-08  9:51                 ` Dmitry A. Kazakov
@ 2019-01-08 18:32                 ` G. B.
  1 sibling, 0 replies; 76+ messages in thread
From: G. B. @ 2019-01-08 18:32 UTC (permalink / raw)


Randy Brukardt <randy@rrsoftware.com> wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:q0pvlp$1vp1$1@gioia.aioe.org...

> That's primarily the job of package specifications, how the contents are 
> structured isn't very relevant from a description standpoint.
> 
> ...
>>> ...
>>>> No, interfaces cannot contain common code except for class-wide one. Is
>>>> that what Randy meant about overhead?
>>> 
>>> Not really. My main point is that you'll never have more than one 
>>> concrete
>>> instance of a generic interface in any individual program (certainly not 
>>> of
>>> an interface like that of a container),
>> 
>> I don't understand this. Usually I have dozens of instantiations of the 
>> same generics with different actual parameters.
> 
> Right, but all of those are *different* interfaces because they have 
> *different* generic parameters. You can't mix those types in any useful way, 
> because you almost always have the generic parameter type(s) involved.
> 
> For instance, for the containers, an interface would have to contain the 
> element type. But that substantially limits reuse, because almost every 
> container instance would have a different element type. You can't even pass 
> just the interface into a generic because you wouldn't be able to call the 
> primitives without knowing the element type. To make such a reuse possible 
> you'd have to pass so many parameters that you are typing instantiations for 
> days. And then the compilation time also would be days. You'd have to be 
> slightly mad to even try it. :-)

For software design, then, does it seem reasonable to assume that the
result of a generic instantiation is not for reuse, but for use? So that,
therefore, if an algorithm can handle different instances of a generic,
this algorithm would specify them through a generic formal?

(Inversion of structure.)


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

* Re: class wide iterable (and indexable)
  2019-01-08  9:51                 ` Dmitry A. Kazakov
@ 2019-01-08 19:25                   ` Björn Lundin
  2019-01-08 23:26                   ` Randy Brukardt
  1 sibling, 0 replies; 76+ messages in thread
From: Björn Lundin @ 2019-01-08 19:25 UTC (permalink / raw)


Den 2019-01-08 kl. 10:51, skrev Dmitry A. Kazakov:
>> A compiler using shared generics could take a lot less time to compile
>> instances because there is little code involved.
> 
> Without any doubt. Worse that that, yes, instances are slow to compile, 
> but I have an impression that merely with-ing compiled instances 
> drastically increases the compile time of a package and the memory used 
> by the compiler. At the end of the dependency chain it becomes minutes 
> to compile a three-liner body. There is something utterly wrong with 
> GNAT there.


We have a package with db-related stuff for each table we have in our 
system - which is about 300. These are auto-generated from xml.

In order to get away from our home brew linked list,
I added a list of type Add.Containers.Doubly_Linked_List.
and for make something else easier we added a hashmap as well.

Now that made the exesize grow so big, that we had to patch ld on AIX
to use more that 1Gb mem...

The resulting exe went from 200 to 280 mb...

Some exefiles were still too big, so at auto-generation these features are
only inserted if the table in question is configured to do so.

Yes, generics is voluminous with gnat.



-- 
Björn


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

* Re: class wide iterable (and indexable)
  2019-01-08  9:51                 ` Dmitry A. Kazakov
  2019-01-08 19:25                   ` Björn Lundin
@ 2019-01-08 23:26                   ` Randy Brukardt
  2019-01-09 17:06                     ` Dmitry A. Kazakov
  1 sibling, 1 reply; 76+ messages in thread
From: Randy Brukardt @ 2019-01-08 23:26 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:q11rqe$dtn$1@gioia.aioe.org...
> On 2019-01-07 22:07, Randy Brukardt wrote:
....
>>> I don't understand this. Usually I have dozens of instantiations of the
>>> same generics with different actual parameters.
>>
>> Right, but all of those are *different* interfaces because they have
>> *different* generic parameters. You can't mix those types in any useful 
>> way,
>> because you almost always have the generic parameter type(s) involved.
>
> Of course I can mix them. Generics are mixed by passing to other generics:
>
>    generic
>       with package X is new P (<>);
>    package Mixer is ...

Sure but this has nothing whatsoever to do with interfaces (the Ada feature, 
as opposed to the concept). You can do this with a typical untagged private 
type, and the effects will be essentially the same.

> The body is valid for all instances of P. And we still have not 
> specialization of generics. So the set of instances cannot be constrained 
> later.
>
> Though, I don't see how it is important to mix or not to mix instances to 
> the question which method of building a class is better. Tagged classes 
> are infinitely better than generic classes.

But that's the point: there aren't any significant tagged classes here, just 
generic classes, because there is only one instance of each class (use of 
formal packages can't change that). There's no point in having more (unless 
you like adding complication for the sake for doing that).

>> For instance, for the containers, an interface would have to contain the
>> element type. But that substantially limits reuse, because almost every
>> container instance would have a different element type. You can't even 
>> pass
>> just the interface into a generic because you wouldn't be able to call 
>> the
>> primitives without knowing the element type. To make such a reuse 
>> possible
>> you'd have to pass so many parameters that you are typing instantiations 
>> for
>> days. And then the compilation time also would be days. You'd have to be
>> slightly mad to even try it. :-)
>
> I don't see your point. You argue that generic-based design of containers 
> is bad. Of course it is bad.

No, I argue that given that there is no realistic alternative (other than to 
abandon strong static typing by deriving everything from a common type, then 
store Object'Class). And that leads to little value for tagged classes, and 
essentially none for interfaces.

If there was a way to have a universal container interface independent of 
the element type (and have that be useful), then the concept would be a lot 
more useful. But that isn't possible in any Ada-like language and retain 
static typing. (If you're willing to completely abandon static typing, then 
everything is possible.)

...
> No, Ada is all OOP as we do
>
>    type I is new Natural; -- Interface

There's no interface (again, I'm only talking about the Ada feature, not 
some concept) here, and no OOP (again, in an Ada sense).

> instead of
>
>    type I is private; -- Nobody knows what
>    function "+" (Left, Right : I) return I;
>    function "-" (Left, Right : I) return I;
>    function "*" (Left, Right : I) return I;
>    function "/" (Left, Right : I) return I;
>    function "0" return I;
>    function "1" return I;
>    function "2" return I;
>    ...

Well, the proposed BigNum packages look just like this, and I've written 
packages like this. (Besides, I note that we started with a BigNum 
interface -- which I tried to be in favor of -- and it was removed because 
of performance concerns. The place where interfaces actually have some use 
is where you have an abstraction with a variety of representations and 
uses -- such as strings or math. That's rare, though, and pretty much only 
happens in the language-defined libraries.)

...
>> And you talk about this a lot, so I don't know what it is that you think 
>> you
>> gain with interfaces that you wouldn't have with a normal record type and
>> primitive operations.
>
> Give me tagged types to freely inherit from and I promise to never use 
> interfaces [*] again! (:-))

Which makes sense to me, since the primary benefit of inherited types is 
implementation reuse. Which interfaces don't allow. I'd surely support this 
position, but I think it is impractical to implement (as well as define 
properly rules for).

...
>>> ----------------------
>>> * GNAT is awfully slow when compiling specifically generic 
>>> instantiations,
>>> and I have lots of them. The more I have, the more I hate them.
>>
>> This is the point where I'd usually suggest trying a different compiler. 
>> :-)
>
> And I usually point out that without Linux/VxWorks support and targets 
> like ARM there is no chance.

Love to do those sorts of things. Know anyone with lots of money that they 
don't know what to do with? (To expand the cross-platform support of 
Janus/Ada just takes money, as I would need to hire people to seriously be 
able to support that. The front-end is designed for such support, especially 
since targetted the U2200 for Unisys [if we can handle a 36-bit machine, we 
can handle anything :-)])

...
>> OTOH, I don't want you to
>> try Janus/Ada (even on the code that don't use actual interfaces), 'cause
>> the way you use generics would inevitably break stuff and I'd hate to 
>> have
>> to debug code like that. :-) :-)
>
> I would gladly use Janus/Ada or ObjectAda if I could. I was a happy user 
> of the latter long ago. Unfortunately cross-platformity is a requirement 
> in these days.

Understood. As you know, that costs $$$, and there aren't enough of those to 
go around.

                Randy.



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

* Re: class wide iterable (and indexable)
  2019-01-08 23:26                   ` Randy Brukardt
@ 2019-01-09 17:06                     ` Dmitry A. Kazakov
  2019-01-09 23:38                       ` Randy Brukardt
  0 siblings, 1 reply; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-09 17:06 UTC (permalink / raw)


On 2019-01-09 00:26, Randy Brukardt wrote:

> But that's the point: there aren't any significant tagged classes here, just
> generic classes, because there is only one instance of each class (use of
> formal packages can't change that).

This is what I do not understand. Instance of a class is a type. Do you 
mean the depth of the hierarch,y probably? Because the number of sibling 
instances is usually large.

> There's no point in having more (unless
> you like adding complication for the sake for doing that).
> 
>>> For instance, for the containers, an interface would have to contain the
>>> element type. But that substantially limits reuse, because almost every
>>> container instance would have a different element type. You can't even
>>> pass
>>> just the interface into a generic because you wouldn't be able to call
>>> the
>>> primitives without knowing the element type. To make such a reuse
>>> possible
>>> you'd have to pass so many parameters that you are typing instantiations
>>> for
>>> days. And then the compilation time also would be days. You'd have to be
>>> slightly mad to even try it. :-)
>>
>> I don't see your point. You argue that generic-based design of containers
>> is bad. Of course it is bad.
> 
> No, I argue that given that there is no realistic alternative (other than to
> abandon strong static typing by deriving everything from a common type, then
> store Object'Class).

It cannot be Object'Class because that includes limited types etc. There 
are lots of constraints on the elements depending on the container, like 
ordering, hashes. These constraints must be spelled in the language, not 
silently assumed. A named interface is a language to spell such 
constraints. #1.

The instances must be further constrained by the user from his side. 
Just like we declare an array type, it does not mean that it can hold 
any elements from the class of definite types. #2.

It seems that you mix constraints #1 with #2.

> If there was a way to have a universal container interface independent of
> the element type (and have that be useful), then the concept would be a lot
> more useful. But that isn't possible in any Ada-like language and retain
> static typing.

I do not understand why. Create an anonymous instance, clone the 
hierarchy, constrain Element'Class to the concrete type T. Everything 
must be done by the compiler in one step as it does for array types.

> The place where interfaces actually have some use
> is where you have an abstraction with a variety of representations and
> uses -- such as strings or math. That's rare, though, and pretty much only
> happens in the language-defined libraries.)

Yes, it depends on the level of reuse. The libraries are massively 
reused. The point is that in a large project you have such things too. 
You must have them otherwise you will not be able to manage complexity.

> Which makes sense to me, since the primary benefit of inherited types is
> implementation reuse. Which interfaces don't allow. I'd surely support this
> position, but I think it is impractical to implement (as well as define
> properly rules for).

Right, this is our main conceptual disagreement. You want to stick to 
generics though they have proven not working. The only alternative is 
inheritance (advanced type system). If only one percent of mental 
efforts were invested into the type system instead, we could have a 
different and IMO better Ada today.

> Love to do those sorts of things. Know anyone with lots of money that they
> don't know what to do with?

True to Ada as a whole. My heart bleeds when I see how much resources 
are wasted on Go, D, C# etc.

>> I would gladly use Janus/Ada or ObjectAda if I could. I was a happy user
>> of the latter long ago. Unfortunately cross-platformity is a requirement
>> in these days.
> 
> Understood. As you know, that costs $$$, and there aren't enough of those to
> go around.

Sure, we need another crazy billionaire who would invest some bits of 
his unearned wealth into Ada rather than in digging tunnels in 
seismically active zones... (:-))

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

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

* Re: class wide iterable (and indexable)
  2019-01-09 17:06                     ` Dmitry A. Kazakov
@ 2019-01-09 23:38                       ` Randy Brukardt
  2019-01-10  8:53                         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 76+ messages in thread
From: Randy Brukardt @ 2019-01-09 23:38 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:q159mg$1q6k$1@gioia.aioe.org...
> On 2019-01-09 00:26, Randy Brukardt wrote:
>
>> But that's the point: there aren't any significant tagged classes here, 
>> just
>> generic classes, because there is only one instance of each class (use of
>> formal packages can't change that).
>
> This is what I do not understand. Instance of a class is a type. Do you 
> mean the depth of the hierarch,y probably? Because the number of sibling 
> instances is usually large.

But the siblings are incompatible with each other (different types, as you 
say). So there is no sharing that can be done between them other than that 
which comes directly from the generic unit itself. That makes any interfaces 
(again, Ada interface feature) involved useless, as they're necessarily 
different than any other such interfaces, which means there isn't anything 
that you can do with them. So why have them at all?

...
>> No, I argue that given that there is no realistic alternative (other than 
>> to
>> abandon strong static typing by deriving everything from a common type, 
>> then
>> store Object'Class).
>
> It cannot be Object'Class because that includes limited types etc. There 
> are lots of constraints on the elements depending on the container, like 
> ordering, hashes. These constraints must be spelled in the language, not 
> silently assumed. A named interface is a language to spell such 
> constraints. #1.

Making the elements much more expensive (because of the need to manage an 
expensive tag) than they otherwise would be. There's a lot of pushback on 
even making language-defined units tagged, because of overhead concerns. 
(Don't buy that myself, but that's the mindset.)

Anyway, #1 has to be part of the contract of the generic. Doesn't make sense 
otherwise. And packaging all of the contracts into a single entity has been 
tried in many ways (that's the original reason for formal packages, the 
so-called signature package) -- and it's always too inflexible. Best to just 
have the individual requirements clearly stated in the profile of the 
generic. (I'd have said "interface", meaning the concept, not the feature, 
but that gets too confusing.)

> The instances must be further constrained by the user from his side. Just 
> like we declare an array type, it does not mean that it can hold any 
> elements from the class of definite types. #2.
>
> It seems that you mix constraints #1 with #2.

#1 has to be part of the contract of the generic; #2 clearly is not. Don't 
see any mixing there.

>> If there was a way to have a universal container interface independent of
>> the element type (and have that be useful), then the concept would be a 
>> lot
>> more useful. But that isn't possible in any Ada-like language and retain
>> static typing.
>
> I do not understand why. Create an anonymous instance, clone the 
> hierarchy, constrain Element'Class to the concrete type T. Everything must 
> be done by the compiler in one step as it does for array types.

Well, separate array types are a mistake given that there are many 
implementations for a sequence. It would be better for them to be a 
container just like all of the others. I.e. I'd make it harder to declare an 
array rather making it easier to declare a container. :-)

I discussed anonymous instances elsewhere; they do great damage to the Ada 
model that everything has a place and to readability.

...
>> Which makes sense to me, since the primary benefit of inherited types is
>> implementation reuse. Which interfaces don't allow. I'd surely support 
>> this
>> position, but I think it is impractical to implement (as well as define
>> properly rules for).
>
> Right, this is our main conceptual disagreement. You want to stick to 
> generics though they have proven not working. The only alternative is 
> inheritance (advanced type system). If only one percent of mental efforts 
> were invested into the type system instead, we could have a different and 
> IMO better Ada today.

A different language, but it wouldn't be Ada. There's no way it could be 
compatible enough, to do so would be to do great violence to that "advanced 
type system". Because most of the details of Ada types aren't advanced in 
any sense. :-)

...
>>> I would gladly use Janus/Ada or ObjectAda if I could. I was a happy user
>>> of the latter long ago. Unfortunately cross-platformity is a requirement
>>> in these days.
>>
>> Understood. As you know, that costs $$$, and there aren't enough of those 
>> to
>> go around.
>
> Sure, we need another crazy billionaire who would invest some bits of his 
> unearned wealth into Ada rather than in digging tunnels in seismically 
> active zones... (:-))

Agreed. :-)

               Randy.


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

* Re: class wide iterable (and indexable)
  2019-01-09 23:38                       ` Randy Brukardt
@ 2019-01-10  8:53                         ` Dmitry A. Kazakov
  2019-01-10 22:14                           ` Randy Brukardt
  0 siblings, 1 reply; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-10  8:53 UTC (permalink / raw)


On 2019-01-10 00:38, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:q159mg$1q6k$1@gioia.aioe.org...
>> On 2019-01-09 00:26, Randy Brukardt wrote:
>>
>>> But that's the point: there aren't any significant tagged classes here, just
>>> generic classes, because there is only one instance of each class (use of
>>> formal packages can't change that).
>>
>> This is what I do not understand. Instance of a class is a type. Do you
>> mean the depth of the hierarch,y probably? Because the number of sibling
>> instances is usually large.
> 
> But the siblings are incompatible with each other (different types, as you
> say).

Possibly.

> So there is no sharing that can be done between them other than that
> which comes directly from the generic unit itself.

If you design them specifically so, but why?

> That makes any interfaces
> (again, Ada interface feature) involved useless, as they're necessarily
> different than any other such interfaces, which means there isn't anything
> that you can do with them. So why have them at all?

You mean declaring an interface inside the generic?

>>> No, I argue that given that there is no realistic alternative (other than
>>> to abandon strong static typing by deriving everything from a common type,
>>> then store Object'Class).
>>
>> It cannot be Object'Class because that includes limited types etc. There
>> are lots of constraints on the elements depending on the container, like
>> ordering, hashes. These constraints must be spelled in the language, not
>> silently assumed. A named interface is a language to spell such
>> constraints. #1.
> 
> Making the elements much more expensive (because of the need to manage an
> expensive tag) than they otherwise would be. There's a lot of pushback on
> even making language-defined units tagged, because of overhead concerns.
> (Don't buy that myself, but that's the mindset.)

Yes, but this is another roadblock. Elements of containers should be 
externally tagged by-value types. That would eliminate the overhead.

> Anyway, #1 has to be part of the contract of the generic. Doesn't make sense
> otherwise. And packaging all of the contracts into a single entity has been
> tried in many ways (that's the original reason for formal packages, the
> so-called signature package) -- and it's always too inflexible. Best to just
> have the individual requirements clearly stated in the profile of the
> generic. (I'd have said "interface", meaning the concept, not the feature,
> but that gets too confusing.)

Sure. It is the same problem in both cases. The solution that would work 
for generics is exactly the interfaces (universal) I am talking about. 
Presently, it is only tagged contracts that are allowed (tagged type or 
Ada interface). And they work perfectly. If we introduced externally 
tagged contracts they would work out of the box just same. Ah, but we 
would not need generics then...

>> The instances must be further constrained by the user from his side. Just
>> like we declare an array type, it does not mean that it can hold any
>> elements from the class of definite types. #2.
>>
>> It seems that you mix constraints #1 with #2.
> 
> #1 has to be part of the contract of the generic; #2 clearly is not. Don't
> see any mixing there.

Then why interfaces are useless? Does it apply to #1 or #2.

>>> If there was a way to have a universal container interface independent of
>>> the element type (and have that be useful), then the concept would be a lot
>>> more useful. But that isn't possible in any Ada-like language and retain
>>> static typing.
>>
>> I do not understand why. Create an anonymous instance, clone the
>> hierarchy, constrain Element'Class to the concrete type T. Everything must
>> be done by the compiler in one step as it does for array types.
> 
> Well, separate array types are a mistake given that there are many
> implementations for a sequence.

There is more than one type of sequences. Sounds like a tautology already.

> It would be better for them to be a
> container just like all of the others. I.e. I'd make it harder to declare an
> array rather making it easier to declare a container. :-)

You make it regular. There is no reason why arrays and containers must 
be treated differently by the language.

> I discussed anonymous instances elsewhere; they do great damage to the Ada
> model that everything has a place and to readability.

But you cannot have safety if you are going to expose all dirty clothes. 
Separation of interface and implementation trumps everything. If an 
instance is for implementation reasons only it must be hidden.

BTW, names of generic instances induce a huge mess in practice. Nobody 
ever remember what name which instance in both directions. You see a 
name with half a dozen dots in it, and struggle to guess what the hell 
is this.

>> Right, this is our main conceptual disagreement. You want to stick to
>> generics though they have proven not working. The only alternative is
>> inheritance (advanced type system). If only one percent of mental efforts
>> were invested into the type system instead, we could have a different and
>> IMO better Ada today.
> 
> A different language, but it wouldn't be Ada.

Yes, it wouldn't be Ada 2012! (:-))

> There's no way it could be
> compatible enough, to do so would be to do great violence to that "advanced
> type system". Because most of the details of Ada types aren't advanced in
> any sense. :-)

We have discussed that many times. I see no reason why it should be 
incompatible. Except, maybe, for a few obscure cases with generics, 
nobody really cares about. There is no more than a half-dozen people in 
the world who know how these must work while they all disagree with each 
other... (:-))

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

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

* Re: class wide iterable (and indexable)
  2019-01-10  8:53                         ` Dmitry A. Kazakov
@ 2019-01-10 22:14                           ` Randy Brukardt
  2019-01-11  9:09                             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 76+ messages in thread
From: Randy Brukardt @ 2019-01-10 22:14 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:q1715k$1fou$1@gioia.aioe.org...
> On 2019-01-10 00:38, Randy Brukardt wrote:
...
>> That makes any interfaces
>> (again, Ada interface feature) involved useless, as they're necessarily
>> different than any other such interfaces, which means there isn't 
>> anything
>> that you can do with them. So why have them at all?
>
> You mean declaring an interface inside the generic?

Yes, because that's the only possibility if the interface has to be 
parameterized by a type in some way (as a container interface has to be). 
And most objects end up being parameterized by a type, else they tend to be 
single purpose (and those types tend not to be like any other).

...
>> Making the elements much more expensive (because of the need to manage an
>> expensive tag) than they otherwise would be. There's a lot of pushback on
>> even making language-defined units tagged, because of overhead concerns.
>> (Don't buy that myself, but that's the mindset.)
>
> Yes, but this is another roadblock. Elements of containers should be 
> externally tagged by-value types. That would eliminate the overhead.

That pushes the cost to other places (i.e. parameter passing instead of 
object declaration). I was including that model in my thinks (not 
necessarily in the thinking of others, of course). Tucker calls this the 
"bump under the carpet" problem. You can move the bump around, but you can't 
get rid of it.

Ada probably can't use the separate tag model because of its insistence on 
supporting redispatching, even in inherited routines. I think you've 
convinced me that model was a mistake, but like many things in existing Ada, 
we're stuck with it short of a drastic (not completely compatible) redesign. 
Note that historically, such redesigns tended to kill languages (Algol 68 
followed Algol 60, but almost everything in the future was derived from 
Algol 60, especially the Wirth Algol W design, which eventually became 
Pascal, which was the major inspiration for Ada).

>> Anyway, #1 has to be part of the contract of the generic. Doesn't make 
>> sense
>> otherwise. And packaging all of the contracts into a single entity has 
>> been
>> tried in many ways (that's the original reason for formal packages, the
>> so-called signature package) -- and it's always too inflexible. Best to 
>> just
>> have the individual requirements clearly stated in the profile of the
>> generic. (I'd have said "interface", meaning the concept, not the 
>> feature,
>> but that gets too confusing.)
>
> Sure. It is the same problem in both cases. The solution that would work 
> for generics is exactly the interfaces (universal) I am talking about. 
> Presently, it is only tagged contracts that are allowed (tagged type or 
> Ada interface). And they work perfectly. If we introduced externally 
> tagged contracts they would work out of the box just same. Ah, but we 
> would not need generics then...

I don't quite see how that would work.

...
>>> I do not understand why. Create an anonymous instance, clone the
>>> hierarchy, constrain Element'Class to the concrete type T. Everything 
>>> must
>>> be done by the compiler in one step as it does for array types.
>>
>> Well, separate array types are a mistake given that there are many
>> implementations for a sequence.
>
> There is more than one type of sequences. Sounds like a tautology already.

The place where interfaces (some more general feature than the one Ada has!) 
are useful is the case where you have to decouple the interface from 
representation. I find this a rare need that shows up mainly in the 
language-defined libraries (obviously YMMV). But it shows up there in a 
mammoth way.

In particular, sequence and string interfaces (again, not like an existing 
Ada feature) are critical, because the representations vary so wildly. Ada 
2020 has gone to great lengths to make arrays and containers work pretty 
much the same way, adding a rather complicated aggregate mechanism and 
adding parallelism to iterators. I start to wonder why (other than 
compatibility) we have built-in array types at all; just make a fixed 
container similar to vectors for what is now arrays.

Whether such interfaces really gain being a general feature (I'm dubious) or 
something built-in (as in current Ada) doesn't change the need for them. 
There's no reason for an array or a vector to be different in any way at 
all -- if the compiler wants to build in support for one or more special 
cases is not relevant to the language design.

In any case, I see the theroetical advantages of having some sort of 
interface mechanism, but I just don't see the uses in practice that make 
them a feature worth all of the implementation and definitional 
complication.

...
>> There's no way it could be
>> compatible enough, to do so would be to do great violence to that 
>> "advanced
>> type system". Because most of the details of Ada types aren't advanced in
>> any sense. :-)
>
> We have discussed that many times. I see no reason why it should be 
> incompatible. Except, maybe, for a few obscure cases with generics, nobody 
> really cares about. There is no more than a half-dozen people in the world 
> who know how these must work while they all disagree with each other... 
> (:-))

Having done this sort of thing for decades now, I have to respectfully 
disagree. There are many rather unusual corner cases in Ada having to do 
with interactions between visibility and resolution and overriding which 
make going much beyond the current model impossible.

For instance, we tried for a long time to work out rules that would allow 
hidden interfaces, but we just could not come up with anything that wasn't 
full of surprising cases or that totally destroyed privacy. That last thing 
anyone wants is their type extensions to do surprising things. We even 
restarted that a few years ago, but the solutions just get ridiculously 
complex.

The sort of model you are suggesting would lead directly to the same sort of 
issues. And the problem with "obscure" corner-cases that are incompatible is 
that they tend to keep people from upgrading even if the language design is 
better off with them. Because almost everyone has code that depends on some 
of those obscure corner cases.

So, to do that sort of overhaul, you'd have to find a willingness to accept 
various incompatibities, and some group motivated enough to work out all of 
the details. Probably need the $$$ again. And it probably would be better 
off to start from scratch semantically in that case, because then you don't 
have to reproduce most of the warts.

                     Randy.



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

* Re: class wide iterable (and indexable)
  2019-01-10 22:14                           ` Randy Brukardt
@ 2019-01-11  9:09                             ` Dmitry A. Kazakov
  2019-01-14 22:59                               ` Randy Brukardt
  0 siblings, 1 reply; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-11  9:09 UTC (permalink / raw)


On 2019-01-10 23:14, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:q1715k$1fou$1@gioia.aioe.org...
>> On 2019-01-10 00:38, Randy Brukardt wrote:
> ...
>>> That makes any interfaces
>>> (again, Ada interface feature) involved useless, as they're necessarily
>>> different than any other such interfaces, which means there isn't
>>> anything
>>> that you can do with them. So why have them at all?
>>
>> You mean declaring an interface inside the generic?
> 
> Yes, because that's the only possibility if the interface has to be
> parameterized by a type in some way (as a container interface has to be).
> And most objects end up being parameterized by a type, else they tend to be
> single purpose (and those types tend not to be like any other).

No, that is the way parametric polymorphism = generics works. Ada 
interfaces are dynamic polymorphism and must be used accordingly. E.g. 
by using an explicit class of elements to be constrained later in the 
instances. (For a hammer everything is a nail)

>>> Making the elements much more expensive (because of the need to manage an
>>> expensive tag) than they otherwise would be. There's a lot of pushback on
>>> even making language-defined units tagged, because of overhead concerns.
>>> (Don't buy that myself, but that's the mindset.)
>>
>> Yes, but this is another roadblock. Elements of containers should be
>> externally tagged by-value types. That would eliminate the overhead.
> 
> That pushes the cost to other places (i.e. parameter passing instead of
> object declaration). I was including that model in my thinks (not
> necessarily in the thinking of others, of course). Tucker calls this the
> "bump under the carpet" problem. You can move the bump around, but you can't
> get rid of it.

It is the same mechanism that is used for passing array bounds. And if 
statically known (and all parents are abstract) the constraint can be 
eliminated altogether, again like with arrays. You might be required to 
adjust inherited operations, but again, this is no different from what 
you do with shared generic bodies.

> Ada probably can't use the separate tag model because of its insistence on
> supporting redispatching, even in inherited routines. I think you've
> convinced me that model was a mistake, but like many things in existing Ada,
> we're stuck with it short of a drastic (not completely compatible) redesign.

There is no view conversions for such types, they are by-value. Thus no 
way to even spell re-dispatch. Conversion to Parent'Class will create a 
new object.

>>> Anyway, #1 has to be part of the contract of the generic. Doesn't make sense
>>> otherwise. And packaging all of the contracts into a single entity has been
>>> tried in many ways (that's the original reason for formal packages, the
>>> so-called signature package) -- and it's always too inflexible. Best to just
>>> have the individual requirements clearly stated in the profile of the
>>> generic. (I'd have said "interface", meaning the concept, not the feature,
>>> but that gets too confusing.)
>>
>> Sure. It is the same problem in both cases. The solution that would work
>> for generics is exactly the interfaces (universal) I am talking about.
>> Presently, it is only tagged contracts that are allowed (tagged type or
>> Ada interface). And they work perfectly. If we introduced externally
>> tagged contracts they would work out of the box just same. Ah, but we
>> would not need generics then...
> 
> I don't quite see how that would work.

That is another question.

I only say that if you want stronger generic contracts then instead of

    generic
       type T is range <>;

you must have

    generic
       type T is new Signed_Integer with private;

Exactly one type of formal generic type. All RM 12.5 to be a two-liner.

> The place where interfaces (some more general feature than the one Ada has!)
> are useful is the case where you have to decouple the interface from
> representation. I find this a rare need that shows up mainly in the
> language-defined libraries (obviously YMMV). But it shows up there in a
> mammoth way.

In my view interface and implementation must be always separated. There 
are cases when the representation could be directly deduced from the 
interface. Only these require no explicit declaration of representation.

> I start to wonder why (other than
> compatibility) we have built-in array types at all; just make a fixed
> container similar to vectors for what is now arrays.

Right. Arrays, records, access types must be interfaces with built-in 
implementations.

> In any case, I see the theroetical advantages of having some sort of
> interface mechanism, but I just don't see the uses in practice that make
> them a feature worth all of the implementation and definitional
> complication.

It would make Ada a very small language. For developers it would ease 
using Ada immensely.

> For instance, we tried for a long time to work out rules that would allow
> hidden interfaces, but we just could not come up with anything that wasn't
> full of surprising cases or that totally destroyed privacy. That last thing
> anyone wants is their type extensions to do surprising things. We even
> restarted that a few years ago, but the solutions just get ridiculously
> complex.

Interfaces should be allowed to be additive with the corresponding rules 
to resolve conflicting implementations. There is an obvious 
contradiction between invisibility and idempotence, e.g. if one entity 
is visible and other is not. Let them add up and require conflict 
resolution in the contexts where both become visible.

> The sort of model you are suggesting would lead directly to the same sort of
> issues. And the problem with "obscure" corner-cases that are incompatible is
> that they tend to keep people from upgrading even if the language design is
> better off with them. Because almost everyone has code that depends on some
> of those obscure corner cases.

Not if the model is universal enough to express all existing quirks. I 
agree that nothing drastic could be resolved at the existing level of 
abstraction. That is why Ada must move one step up.

> So, to do that sort of overhaul, you'd have to find a willingness to accept
> various incompatibities, and some group motivated enough to work out all of
> the details. Probably need the $$$ again. And it probably would be better
> off to start from scratch semantically in that case, because then you don't
> have to reproduce most of the warts.

No, I don't believe that either. See how people keep on creating C. 
There is a dozen of C-like languages redesigned from scratch, but the 
warts are all there.

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

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

* Re: class wide iterable (and indexable)
  2019-01-11  9:09                             ` Dmitry A. Kazakov
@ 2019-01-14 22:59                               ` Randy Brukardt
  2019-01-15  9:34                                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 76+ messages in thread
From: Randy Brukardt @ 2019-01-14 22:59 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:q19mh2$19lu$1@gioia.aioe.org...
> On 2019-01-10 23:14, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:q1715k$1fou$1@gioia.aioe.org...
>>> On 2019-01-10 00:38, Randy Brukardt wrote:
>> ...
>>>> That makes any interfaces
>>>> (again, Ada interface feature) involved useless, as they're necessarily
>>>> different than any other such interfaces, which means there isn't
>>>> anything
>>>> that you can do with them. So why have them at all?
>>>
>>> You mean declaring an interface inside the generic?
>>
>> Yes, because that's the only possibility if the interface has to be
>> parameterized by a type in some way (as a container interface has to be).
>> And most objects end up being parameterized by a type, else they tend to 
>> be
>> single purpose (and those types tend not to be like any other).
>
> No, that is the way parametric polymorphism = generics works. Ada 
> interfaces are dynamic polymorphism and must be used accordingly. E.g. by 
> using an explicit class of elements to be constrained later in the 
> instances. (For a hammer everything is a nail)

Perhaps, but then you can't build anything really generic (like the 
containers or Direct_IO). Forcing everything into a class just for the sake 
of that just replaces one set of problems with a different set.

>>>> Making the elements much more expensive (because of the need to manage 
>>>> an
>>>> expensive tag) than they otherwise would be. There's a lot of pushback 
>>>> on
>>>> even making language-defined units tagged, because of overhead 
>>>> concerns.
>>>> (Don't buy that myself, but that's the mindset.)
>>>
>>> Yes, but this is another roadblock. Elements of containers should be
>>> externally tagged by-value types. That would eliminate the overhead.
>>
>> That pushes the cost to other places (i.e. parameter passing instead of
>> object declaration). I was including that model in my thinks (not
>> necessarily in the thinking of others, of course). Tucker calls this the
>> "bump under the carpet" problem. You can move the bump around, but you 
>> can't
>> get rid of it.
>
> It is the same mechanism that is used for passing array bounds. And if 
> statically known (and all parents are abstract) the constraint can be 
> eliminated altogether, again like with arrays. You might be required to 
> adjust inherited operations, but again, this is no different from what you 
> do with shared generic bodies.

Sure, but passing array bounds is pretty expensive. It's certainly more 
expensive than having a tag component, at least unless the number of objects 
 >> number of calls. Again, you're just trading one set of costs for a 
different set.

>> Ada probably can't use the separate tag model because of its insistence 
>> on
>> supporting redispatching, even in inherited routines. I think you've
>> convinced me that model was a mistake, but like many things in existing 
>> Ada,
>> we're stuck with it short of a drastic (not completely compatible) 
>> redesign.
>
> There is no view conversions for such types, they are by-value. Thus no 
> way to even spell re-dispatch. Conversion to Parent'Class will create a 
> new object.

Not necessarily, since we're also talking about untagged composite types. 
One hopes that we're not going to force strings or coordinates to be passed 
by copy (that would cause a lot of extra copying).

Remember that program performance can be roughly determined by the amount of 
memory operations that it does. The more copying, the worse the performance. 
Only elementary types are roughly free to copy.

...
...
>> For instance, we tried for a long time to work out rules that would allow
>> hidden interfaces, but we just could not come up with anything that 
>> wasn't
>> full of surprising cases or that totally destroyed privacy. That last 
>> thing
>> anyone wants is their type extensions to do surprising things. We even
>> restarted that a few years ago, but the solutions just get ridiculously
>> complex.
>
> Interfaces should be allowed to be additive with the corresponding rules 
> to resolve conflicting implementations. There is an obvious contradiction 
> between invisibility and idempotence, e.g. if one entity is visible and 
> other is not. Let them add up and require conflict resolution in the 
> contexts where both become visible.

What would that look like? Currently, you can only resolve conflicts with 
type names, and that certainly would not be enough in this case (the name of 
the interface being the same for every copy, as well as the type that has 
all of these interfaces). Numbering isn't going be reliable (the number of 
copies could differ for every view). So how could you deal with such 
conflicts?

...
>> So, to do that sort of overhaul, you'd have to find a willingness to 
>> accept
>> various incompatibities, and some group motivated enough to work out all 
>> of
>> the details. Probably need the $$$ again. And it probably would be better
>> off to start from scratch semantically in that case, because then you 
>> don't
>> have to reproduce most of the warts.
>
> No, I don't believe that either. See how people keep on creating C. There 
> is a dozen of C-like languages redesigned from scratch, but the warts are 
> all there.

The people doing that like a lot of about C already (why the mass hysteria 
on that, I don't know. Perhaps they don't even know that you can do 
better?). If I personally redesigned Ada, it would be a lot like the current 
Ada with some warts removed (strings and arrays in particular). I generally 
like the way Ada works, as I'm sure you know; I don't think a lot needs to 
be done to the type system. Clearly your vision is rather different.

                     Randy.




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

* Re: class wide iterable (and indexable)
  2019-01-14 22:59                               ` Randy Brukardt
@ 2019-01-15  9:34                                 ` Dmitry A. Kazakov
  2019-01-18 15:48                                   ` Olivier Henley
  0 siblings, 1 reply; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-15  9:34 UTC (permalink / raw)


On 2019-01-14 23:59, Randy Brukardt wrote:

> Perhaps, but then you can't build anything really generic (like the
> containers or Direct_IO).

Especially them! Generics have no place in containers and I/O. It is 
pure insanity.

> Forcing everything into a class just for the sake
> of that just replaces one set of problems with a different set.

Generics types form classes. You cannot avoid classes, you only can 
change the means of building them.

>> It is the same mechanism that is used for passing array bounds. And if
>> statically known (and all parents are abstract) the constraint can be
>> eliminated altogether, again like with arrays. You might be required to
>> adjust inherited operations, but again, this is no different from what you
>> do with shared generic bodies.
> 
> Sure, but passing array bounds is pretty expensive. It's certainly more
> expensive than having a tag component, at least unless the number of objects
> number of calls. Again, you're just trading one set of costs for a
> different set.

I mean that when array is statically constrained bounds are removed. The 
case with containers that the element type is constrained and the same 
mechanism can be used to avoid overhead.

>>> Ada probably can't use the separate tag model because of its insistence
>>> on
>>> supporting redispatching, even in inherited routines. I think you've
>>> convinced me that model was a mistake, but like many things in existing
>>> Ada,
>>> we're stuck with it short of a drastic (not completely compatible)
>>> redesign.
>>
>> There is no view conversions for such types, they are by-value. Thus no
>> way to even spell re-dispatch. Conversion to Parent'Class will create a
>> new object.
> 
> Not necessarily, since we're also talking about untagged composite types.
> One hopes that we're not going to force strings or coordinates to be passed
> by copy (that would cause a lot of extra copying).

It is OK. But that would not bring view conversion back. The tag will be 
taken from the designated data type and tag + reference will passed as 
class-wide. It is tag + value or tag + reference, the semantics will be 
same.

>> Interfaces should be allowed to be additive with the corresponding rules
>> to resolve conflicting implementations. There is an obvious contradiction
>> between invisibility and idempotence, e.g. if one entity is visible and
>> other is not. Let them add up and require conflict resolution in the
>> contexts where both become visible.
> 
> What would that look like? Currently, you can only resolve conflicts with
> type names, and that certainly would not be enough in this case (the name of
> the interface being the same for every copy, as well as the type that has
> all of these interfaces). Numbering isn't going be reliable (the number of
> copies could differ for every view). So how could you deal with such
> conflicts?

I don't know. There should be some nice syntax invented to replace 
conflicting names (of interfaces + their operations and members) at the 
type declaration point.

>> No, I don't believe that either. See how people keep on creating C. There
>> is a dozen of C-like languages redesigned from scratch, but the warts are
>> all there.
> 
> The people doing that like a lot of about C already (why the mass hysteria
> on that, I don't know. Perhaps they don't even know that you can do
> better?). If I personally redesigned Ada, it would be a lot like the current
> Ada with some warts removed (strings and arrays in particular).

See, that is the same mindset! (:-))

> I generally
> like the way Ada works, as I'm sure you know; I don't think a lot needs to
> be done to the type system. Clearly your vision is rather different.

I think that the type system must be generalized and extended, not 
changed. What you say about strings and arrays is what I would as well. 
But I would simply make them library-level things because the extended 
type system would be capable to make them such.

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


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

* Re: class wide iterable (and indexable)
  2019-01-15  9:34                                 ` Dmitry A. Kazakov
@ 2019-01-18 15:48                                   ` Olivier Henley
  2019-01-18 16:08                                     ` Dmitry A. Kazakov
  2019-01-21 23:15                                     ` Randy Brukardt
  0 siblings, 2 replies; 76+ messages in thread
From: Olivier Henley @ 2019-01-18 15:48 UTC (permalink / raw)



> > The people doing that like a lot of about C already (why the mass hysteria
> > on that, I don't know. Perhaps they don't even know that you can do
> > better?). If I personally redesigned Ada, it would be a lot like the current
> > Ada with some warts removed (strings and arrays in particular).
> 
> See, that is the same mindset! (:-))

What are the warts for strings and arrays?


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

* Re: class wide iterable (and indexable)
  2019-01-18 15:48                                   ` Olivier Henley
@ 2019-01-18 16:08                                     ` Dmitry A. Kazakov
  2019-01-18 16:29                                       ` Olivier Henley
  2019-01-21 23:15                                     ` Randy Brukardt
  1 sibling, 1 reply; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-18 16:08 UTC (permalink / raw)


On 2019-01-18 16:48, Olivier Henley wrote:
> 
>>> The people doing that like a lot of about C already (why the mass hysteria
>>> on that, I don't know. Perhaps they don't even know that you can do
>>> better?). If I personally redesigned Ada, it would be a lot like the current
>>> Ada with some warts removed (strings and arrays in particular).
>>
>> See, that is the same mindset! (:-))
> 
> What are the warts for strings and arrays?

Array interface is not separated from implementation/representation. The 
problems with String encoding is a consequence of. You cannot have 
differently encoded Strings with the same interface. You cannot have two 
array interfaces for the same String (array of characters vs. array of 
encoding units, e.g. of code points).

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

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

* Re: class wide iterable (and indexable)
  2019-01-18 16:08                                     ` Dmitry A. Kazakov
@ 2019-01-18 16:29                                       ` Olivier Henley
  2019-01-18 16:54                                         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 76+ messages in thread
From: Olivier Henley @ 2019-01-18 16:29 UTC (permalink / raw)


> Array interface is not separated from implementation/representation. The 
> problems with String encoding is a consequence of. You cannot have 
> differently encoded Strings with the same interface. You cannot have two 
> array interfaces for the same String (array of characters vs. array of 
> encoding units, e.g. of code points).

Ok but is it not the intended purpose of an 'array' to be/stay a 'primitive memory mapping construct'?

Could the type of array... then the string, you wish for be added to the language? 


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

* Re: class wide iterable (and indexable)
  2019-01-18 16:29                                       ` Olivier Henley
@ 2019-01-18 16:54                                         ` Dmitry A. Kazakov
  2019-01-18 17:31                                           ` Olivier Henley
  0 siblings, 1 reply; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-18 16:54 UTC (permalink / raw)


On 2019-01-18 17:29, Olivier Henley wrote:
>> Array interface is not separated from implementation/representation. The
>> problems with String encoding is a consequence of. You cannot have
>> differently encoded Strings with the same interface. You cannot have two
>> array interfaces for the same String (array of characters vs. array of
>> encoding units, e.g. of code points).
> 
> Ok but is it not the intended purpose of an 'array' to be/stay a 'primitive memory mapping construct'?

That is a purpose of a builtin array, a building block of user types 
implementation. *If* a builtin array is all the user needs, fine. That 
is 80% of the cases. But the example of containers represent multiple 
cases when just primitive memory mapping is not enough. Concurrently 
accessed arrays is another example. Externally kept arrays, e.g. 
interfacing other language, DB, network etc is yet another example.

The same applies to record types, access types, enumeration types, 
numeric types, subroutine types, task types, protected types. Each one 
must have an interface which can be used together with a custom 
implementation or the builtin implementation.

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

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

* Re: class wide iterable (and indexable)
  2019-01-18 16:54                                         ` Dmitry A. Kazakov
@ 2019-01-18 17:31                                           ` Olivier Henley
  2019-01-18 18:51                                             ` Shark8
  2019-01-18 20:09                                             ` Dmitry A. Kazakov
  0 siblings, 2 replies; 76+ messages in thread
From: Olivier Henley @ 2019-01-18 17:31 UTC (permalink / raw)


> The same applies to record types, access types, enumeration types, 
> numeric types, subroutine types, task types, protected types. Each one 
> must have an interface which can be used together with a custom 
> implementation or the builtin implementation.

Any language that does it well, example?


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

* Re: class wide iterable (and indexable)
  2019-01-18 17:31                                           ` Olivier Henley
@ 2019-01-18 18:51                                             ` Shark8
  2019-01-18 20:09                                             ` Dmitry A. Kazakov
  1 sibling, 0 replies; 76+ messages in thread
From: Shark8 @ 2019-01-18 18:51 UTC (permalink / raw)


On Friday, January 18, 2019 at 10:31:24 AM UTC-7, Olivier Henley wrote:
> 
> Any language that does it well, example?

I can't really think of any off the top of my head. The only one that I suspect *might* would be ML (Standard ML, or OCaml), though that's only from reading about it, not any actual usage and not in a lot of depth.

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

* Re: class wide iterable (and indexable)
  2019-01-18 17:31                                           ` Olivier Henley
  2019-01-18 18:51                                             ` Shark8
@ 2019-01-18 20:09                                             ` Dmitry A. Kazakov
  1 sibling, 0 replies; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-18 20:09 UTC (permalink / raw)


On 2019-01-18 18:31, Olivier Henley wrote:
>> The same applies to record types, access types, enumeration types,
>> numeric types, subroutine types, task types, protected types. Each one
>> must have an interface which can be used together with a custom
>> implementation or the builtin implementation.
> 
> Any language that does it well, example?

I would not expect any strongly typed language doing types better than 
Ada. So no, it is Ada's job to keep the candle burning...

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


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

* Re: class wide iterable (and indexable)
  2019-01-18 15:48                                   ` Olivier Henley
  2019-01-18 16:08                                     ` Dmitry A. Kazakov
@ 2019-01-21 23:15                                     ` Randy Brukardt
  2019-01-22  8:56                                       ` Dmitry A. Kazakov
  2019-01-22 17:04                                       ` Jeffrey R. Carter
  1 sibling, 2 replies; 76+ messages in thread
From: Randy Brukardt @ 2019-01-21 23:15 UTC (permalink / raw)


"Olivier Henley" <olivier.henley@gmail.com> wrote in message 
news:75328dc5-fc59-4228-b77e-77ba6e5101c3@googlegroups.com...
>
>> > The people doing that like a lot of about C already (why the mass 
>> > hysteria
>> > on that, I don't know. Perhaps they don't even know that you can do
>> > better?). If I personally redesigned Ada, it would be a lot like the 
>> > current
>> > Ada with some warts removed (strings and arrays in particular).
>>
>> See, that is the same mindset! (:-))
>
> What are the warts for strings and arrays?

A string is not really an array. That idea made some sense in Ada 83, when 
the only portable character set was 7-bit ASCII. But today there are many 
representations, and treating each one of them as a different unrelated type 
leads to Wide_Wide_ nonsense, and even that doesn't have a decent solution 
for UTF-8 and UTF-16 encoded text.

Moreover, if you view an array as a basic building block, not something of 
interest by itself, you don't need fancy array operations that are mainly 
useful for strings (ordering operators, slices, etc.).

For Ada, of course, these things are a sunk cost, but in a new Ada-like 
language, they would be impedements to getting an implementation built. 
Moreover, in a new Ada-like language, it would make the most sense to 
completely unify containers and arrays, which would mean that arrays would 
be more like Vectors than like Ada arrays. For instance, in a Vector, the 
lower bound is fixed for all values of a particular type. That would 
eliminate a lot of programming errors that happen in Ada programs (many 
programs fail to deal with unusual lower bounds, because it's hard to get 
right).

                                                   Randy.


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

* Re: class wide iterable (and indexable)
  2019-01-21 23:15                                     ` Randy Brukardt
@ 2019-01-22  8:56                                       ` Dmitry A. Kazakov
  2019-01-22 22:00                                         ` Randy Brukardt
  2019-01-22 17:04                                       ` Jeffrey R. Carter
  1 sibling, 1 reply; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-22  8:56 UTC (permalink / raw)


On 2019-01-22 00:15, Randy Brukardt wrote:
> For instance, in a Vector, the
> lower bound is fixed for all values of a particular type. That would
> eliminate a lot of programming errors that happen in Ada programs (many
> programs fail to deal with unusual lower bounds, because it's hard to get
> right).

I disagree. It would make array slices more difficult to use. Presently 
we can do things like

    Read (Buffer (From..To), Last);

Foo can move the index Last and this is the same index as outside in the 
caller because indices do not slide. If you make the lower bound fixed, 
indices would slide and that would require a lot of index arithmetic 
upon calling subprograms on slices. This would be far more error-prone 
than occasionally forgetting to use Buffer'First instead of 1.

P.S. If we wanted safety we could use private numeric types for array 
indices and alternative array constructors with the number of elements 
(universal integer) instead of a range. That would preclude any literals 
appearing in place of an index.

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


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

* Re: class wide iterable (and indexable)
  2019-01-21 23:15                                     ` Randy Brukardt
  2019-01-22  8:56                                       ` Dmitry A. Kazakov
@ 2019-01-22 17:04                                       ` Jeffrey R. Carter
  2019-01-22 22:02                                         ` Randy Brukardt
  1 sibling, 1 reply; 76+ messages in thread
From: Jeffrey R. Carter @ 2019-01-22 17:04 UTC (permalink / raw)


On 1/22/19 12:15 AM, Randy Brukardt wrote:
> 
> Moreover, in a new Ada-like language, it would make the most sense to
> completely unify containers and arrays, which would mean that arrays would
> be more like Vectors than like Ada arrays. For instance, in a Vector, the
> lower bound is fixed for all values of a particular type. That would
> eliminate a lot of programming errors that happen in Ada programs (many
> programs fail to deal with unusual lower bounds, because it's hard to get
> right).

Ada has always had the ability to define array-like types with a fixed lower bound:

type String_From_1 (Length : Natural) is record
    Value : String (1 .. Length);
end record;

I use such constructs when appropriate (in mathematics, for example, matrices 
and vectors have indices with lower values of 1, and a decent implementation 
should reflect and enforce that). One might argue that the reason they're not 
used more often is because of the value of having array types with variable 
lower bounds, but I doubt it.

-- 
Jeff Carter
"He didn't get that nose from playing ping-pong."
Never Give a Sucker an Even Break
110

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

* Re: class wide iterable (and indexable)
  2019-01-22  8:56                                       ` Dmitry A. Kazakov
@ 2019-01-22 22:00                                         ` Randy Brukardt
  2019-01-23  8:14                                           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 76+ messages in thread
From: Randy Brukardt @ 2019-01-22 22:00 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:q26lsh$1ee3$1@gioia.aioe.org...
> On 2019-01-22 00:15, Randy Brukardt wrote:
>> For instance, in a Vector, the
>> lower bound is fixed for all values of a particular type. That would
>> eliminate a lot of programming errors that happen in Ada programs (many
>> programs fail to deal with unusual lower bounds, because it's hard to get
>> right).
>
> I disagree. It would make array slices more difficult to use.

Array slices as defined in Ada aren't worth the substantial implementation 
complexity. I would replace them by slicing functions, and the bounds are 
lost.

> Presently we can do things like
>
>    Read (Buffer (From..To), Last);

Surely. But "Last" is a weird Ada-ism that exists solely because array 
bounds are so generally accessible. It is much more natural (and sensible 
for most uses) to return the count of characters read.

> Foo can move the index Last and this is the same index as outside in the 
> caller because indices do not slide. If you make the lower bound fixed, 
> indices would slide and that would require a lot of index arithmetic upon 
> calling subprograms on slices. This would be far more error-prone than 
> occasionally forgetting to use Buffer'First instead of 1.

True, in the rare case where that matters. But most of the time, one has to 
do that math to convert "Last" into a number of character read. So this is a 
wash to me - some things are easier, som things are harder. (Again, "Last" 
is an odd Ada-ism, specs would return a character count, not some array 
index.)

                              Randy.


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

* Re: class wide iterable (and indexable)
  2019-01-22 17:04                                       ` Jeffrey R. Carter
@ 2019-01-22 22:02                                         ` Randy Brukardt
  2019-01-23 18:00                                           ` Jeffrey R. Carter
  2019-01-23 20:14                                           ` Shark8
  0 siblings, 2 replies; 76+ messages in thread
From: Randy Brukardt @ 2019-01-22 22:02 UTC (permalink / raw)


"Jeffrey R. Carter" <spam.jrcarter.not@spam.not.acm.org> wrote in message 
news:q27if9$b0r$1@dont-email.me...
> On 1/22/19 12:15 AM, Randy Brukardt wrote:
>>
>> Moreover, in a new Ada-like language, it would make the most sense to
>> completely unify containers and arrays, which would mean that arrays 
>> would
>> be more like Vectors than like Ada arrays. For instance, in a Vector, the
>> lower bound is fixed for all values of a particular type. That would
>> eliminate a lot of programming errors that happen in Ada programs (many
>> programs fail to deal with unusual lower bounds, because it's hard to get
>> right).
>
> Ada has always had the ability to define array-like types with a fixed 
> lower bound:
>
> type String_From_1 (Length : Natural) is record
>    Value : String (1 .. Length);
> end record;
>
> I use such constructs when appropriate (in mathematics, for example, 
> matrices and vectors have indices with lower values of 1, and a decent 
> implementation should reflect and enforce that). One might argue that the 
> reason they're not used more often is because of the value of having array 
> types with variable lower bounds, but I doubt it.

They're not used more often because this fixes the length, and prevents 
operations on items with different lengths. Again, a string is not an 
array -- a Vector is a better model for a string.

                               Randy.



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

* Re: class wide iterable (and indexable)
  2019-01-22 22:00                                         ` Randy Brukardt
@ 2019-01-23  8:14                                           ` Dmitry A. Kazakov
  0 siblings, 0 replies; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-23  8:14 UTC (permalink / raw)


On 2019-01-22 23:00, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:q26lsh$1ee3$1@gioia.aioe.org...
>> On 2019-01-22 00:15, Randy Brukardt wrote:
>>> For instance, in a Vector, the
>>> lower bound is fixed for all values of a particular type. That would
>>> eliminate a lot of programming errors that happen in Ada programs (many
>>> programs fail to deal with unusual lower bounds, because it's hard to get
>>> right).
>>
>> I disagree. It would make array slices more difficult to use.
> 
> Array slices as defined in Ada aren't worth the substantial implementation
> complexity. I would replace them by slicing functions, and the bounds are
> lost.

The reverse. A container without slices is half useless to me. BTW, nD 
arrays must support slicing, subarrays, subplanes etc.

>> Presently we can do things like
>>
>>     Read (Buffer (From..To), Last);
> 
> Surely. But "Last" is a weird Ada-ism that exists solely because array
> bounds are so generally accessible. It is much more natural (and sensible
> for most uses) to return the count of characters read.

No, because it is a break of the abstraction, unsafe and error-prone.

>> Foo can move the index Last and this is the same index as outside in the
>> caller because indices do not slide. If you make the lower bound fixed,
>> indices would slide and that would require a lot of index arithmetic upon
>> calling subprograms on slices. This would be far more error-prone than
>> occasionally forgetting to use Buffer'First instead of 1.
> 
> True, in the rare case where that matters. But most of the time, one has to
> do that math to convert "Last" into a number of character read. So this is a
> wash to me - some things are easier, som things are harder. (Again, "Last"
> is an odd Ada-ism, specs would return a character count, not some array
> index.)

You want to get rid of indices and have only positions. Positions is not 
a substitute to indices. With multiple interfaces there would be no 
problem to have a positional view on the array. Which is not an array 
interface anymore. It would be an interface of a tuple. Ada does not 
have builtoin tuples, but it could have them. Just do not force 
everything into it.

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

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

* Re: class wide iterable (and indexable)
  2019-01-22 22:02                                         ` Randy Brukardt
@ 2019-01-23 18:00                                           ` Jeffrey R. Carter
  2019-01-23 20:14                                           ` Shark8
  1 sibling, 0 replies; 76+ messages in thread
From: Jeffrey R. Carter @ 2019-01-23 18:00 UTC (permalink / raw)


On 1/22/19 11:02 PM, Randy Brukardt wrote:
> 
> They're not used more often because this fixes the length, and prevents
> operations on items with different lengths. Again, a string is not an
> array -- a Vector is a better model for a string.

I suspect we're talking about 2 different things.

The length is fixed just as it is for all array objects. I'm talking about a way 
to get arrays (current Ada meaning) with a fixed lower bound. Things with a 
variable length are something else altogether.

I used String simply because it was a convenient array type to use in the 
example. This made the example easier to understand because it didn't need an 
extra type definition that is irrelevant to explaining the concept.

I'm not discussing whether this is a useful implementation for strings. (A 
string is a sequence of characters, and one use of an array is sequences, so an 
array may be a suitable implementation for a string. I suspect many of your 
problems with strings are really problems with characters.)

With all that understood (I hope), I can restate my question as: Why do those 
who use arrays, and have difficulty with them having variable lower bounds, not 
use such constructs more often instead? Is it because the value of having 
constant indices across slices outweighs the negatives of variable lower bounds?

-- 
Jeff Carter
"This scene's supposed to be in a saloon, but
the censor cut it out. It'll play just as well
this way." [in a soda fountain]
Never Give a Sucker an Even Break
113

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

* Re: class wide iterable (and indexable)
  2019-01-22 22:02                                         ` Randy Brukardt
  2019-01-23 18:00                                           ` Jeffrey R. Carter
@ 2019-01-23 20:14                                           ` Shark8
  2019-01-23 22:47                                             ` Randy Brukardt
  1 sibling, 1 reply; 76+ messages in thread
From: Shark8 @ 2019-01-23 20:14 UTC (permalink / raw)


Wouldn't this be a non-issue if we could Static_Predicate Array-types like so?

Type Some_String is Array(Positive range <>) of Character
  with Static-Predicate => Some_String'First = 1;


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

* Re: class wide iterable (and indexable)
  2019-01-23 20:14                                           ` Shark8
@ 2019-01-23 22:47                                             ` Randy Brukardt
  2019-01-24 17:11                                               ` Dmitry A. Kazakov
  2019-01-28 15:54                                               ` Shark8
  0 siblings, 2 replies; 76+ messages in thread
From: Randy Brukardt @ 2019-01-23 22:47 UTC (permalink / raw)


"Shark8" <onewingedshark@gmail.com> wrote in message 
news:9eedf818-8bfb-465b-afe5-aa3fb0525948@googlegroups.com...
> Wouldn't this be a non-issue if we could Static_Predicate Array-types like 
> so?
>
> Type Some_String is Array(Positive range <>) of Character
>  with Static-Predicate => Some_String'First = 1;

The idea of a static predicate is for them to stand-in for proper set 
constraints (I would have preferred the latter, but I was alone on that), so 
they don't have anything to do with array bounds.

You can do this with Dynamic_Predicates, but it doesn't make the slices act 
differently, so problems will ensue. Changing the semantics of slices 
(essentially to force sliding everywhere) would require some sort of 
declaration beyond just the predicate.

                      Randy.




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

* Re: class wide iterable (and indexable)
  2019-01-23 22:47                                             ` Randy Brukardt
@ 2019-01-24 17:11                                               ` Dmitry A. Kazakov
  2019-01-28 15:54                                               ` Shark8
  1 sibling, 0 replies; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-24 17:11 UTC (permalink / raw)


On 2019-01-23 23:47, Randy Brukardt wrote:

> You can do this with Dynamic_Predicates, but it doesn't make the slices act
> differently, so problems will ensue. Changing the semantics of slices
> (essentially to force sliding everywhere) would require some sort of
> declaration beyond just the predicate.

or making (x..y) a proper operation:

    function "(..)" (A : Array_Type; From, To : Index_Type)
       return Array_Type is
    begin
       return Result : Array_Type (1..(To - From) + 1) := A (From, To);
    end "(..)";

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


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

* Re: class wide iterable (and indexable)
  2019-01-02 15:48 class wide iterable (and indexable) George Shapovalov
  2019-01-02 17:39 ` Simon Wright
@ 2019-01-26 22:11 ` George Shapovalov
  2019-01-26 22:14   ` George Shapovalov
  1 sibling, 1 reply; 76+ messages in thread
From: George Shapovalov @ 2019-01-26 22:11 UTC (permalink / raw)


Original poster here.
I think I did it again - that is broke gnat again. 

But first a small update: I have cleaned up and systematized the original code somewhat and added the description. Plus I added the complete "demo" code of the basic mix-in situations. No proper description yet though. The general idea is to create a small depository of common composition situations, to have some base tested code that can be expanded upon.. Two sample compositions are implemented in the code already: the basic mix-ins and the "list interface" over which Ada.Containers.Vectors.Vector can be directly overlayed (among other implementations).
The link to the project is here:
https://github.com/gerr135/ada_composition
(renamed from original ada_gems to avoid name clash with existing Ada Gems by AdaCore).

In trying to expand on that last example - the indexable/iterable and overlayable by existing type interface, I have stumbled upon a rather weird behavior of compiled code. The expansion deals with trying to tie a type hierarchy to the hierarchy of list implementations - not to have a single generic type at the top and children units using the same. Instead this code has a generic interface at the top, and children take specific types implementing interface at the top. This works fine (with minimal code changes in the "library" itself from the previous case) for the basic composition types (record encapsulating wither array of ACV.Vector). But when I try to pass ACV.Vector overlais directly over interface as a generic parameter, it seems the compiler gets confused. While passing the constructed Vector into the List object it raises run-time exception:
raised PROGRAM_ERROR : adjust/finalize raised STORAGE_ERROR: System.Memory.Alloc: heap exhausted

which is rather weird in itself. What's more, a simple whitespace change - splitting the line of code directly above into two (inserting line break between two trivial TEXT_IO ops that are in the same line in the code) changes that error into:
raised PROGRAM_ERROR : adjust/finalize raised STORAGE_ERROR: stack overflow or erroneous memory access

The line of code in question is this:
ld(i) := Base_Interface'Class(set_idx_vector(i));

the setter runs fine (and identical setter for a differently composed version of the base type completes fine *and* allows the constructed object to be passed), but attempt to assign the constructed object to the List container blows up with that STORAGE_ERROR. Please note: only the last variant is affected, that is List composition directly overlaying ACV.Vector over List_Interface, *but not* a more common encapsulation having ACV.Vector a record entry.

Unfortunately. as before, I cannot post just a line or two of code that would reproduce the entire situation. Providing indexing and iteration for the entire type hierarchy takes some code. Please see this specific link for the appropriate part:
https://github.com/gerr135/ada_composition/tree/master/list_combo

This *is* the minimal code that reproduces the situation as far as I can tell..

I cannot see why this specific variant would be "wrong" in some way - the overal interface is the same for all 3 variants. Plus that weird behavior (sensitivity to whitespace) makes me suspect some problem with gnat here. But maybe I overlooked something.
Any ideas are appreciated. 
Thank you!


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

* Re: class wide iterable (and indexable)
  2019-01-26 22:11 ` George Shapovalov
@ 2019-01-26 22:14   ` George Shapovalov
  0 siblings, 0 replies; 76+ messages in thread
From: George Shapovalov @ 2019-01-26 22:14 UTC (permalink / raw)


On Saturday, January 26, 2019 at 11:11:40 PM UTC+1, George Shapovalov wrote:
> The line of code in question is this:
> ld(i) := Base_Interface'Class(set_idx_vector(i));
> 
A small note: the cited line of code is at the end of the "main" file test_list_combo.adb. I marked it with comments highlighting the issue.

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

* Re: class wide iterable (and indexable)
  2019-01-23 22:47                                             ` Randy Brukardt
  2019-01-24 17:11                                               ` Dmitry A. Kazakov
@ 2019-01-28 15:54                                               ` Shark8
  2019-01-28 17:23                                                 ` Dmitry A. Kazakov
  1 sibling, 1 reply; 76+ messages in thread
From: Shark8 @ 2019-01-28 15:54 UTC (permalink / raw)


On Wednesday, January 23, 2019 at 3:47:43 PM UTC-7, Randy Brukardt wrote:
> "Shark8" wrote in message 
> news:9eedf818-8bfb-465b-afe5-aa3fb0525948...
> > Wouldn't this be a non-issue if we could Static_Predicate Array-types like 
> > so?
> >
> > Type Some_String is Array(Positive range <>) of Character
> >  with Static-Predicate => Some_String'First = 1;
> 
> The idea of a static predicate is for them to stand-in for proper set 
> constraints (I would have preferred the latter, but I was alone on that), so 
> they don't have anything to do with array bounds.

What do you mean by "proper set constraints"? [And how would they look?]
Things like {x| x in {2**y where y in 0..15} }? (X in 1|2|4|8|16|..|32_768)


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

* Re: class wide iterable (and indexable)
  2019-01-28 15:54                                               ` Shark8
@ 2019-01-28 17:23                                                 ` Dmitry A. Kazakov
  0 siblings, 0 replies; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-28 17:23 UTC (permalink / raw)


On 2019-01-28 16:54, Shark8 wrote:
> On Wednesday, January 23, 2019 at 3:47:43 PM UTC-7, Randy Brukardt wrote:
>> "Shark8" wrote in message
>> news:9eedf818-8bfb-465b-afe5-aa3fb0525948...
>>> Wouldn't this be a non-issue if we could Static_Predicate Array-types like
>>> so?
>>>
>>> Type Some_String is Array(Positive range <>) of Character
>>>   with Static-Predicate => Some_String'First = 1;
>>
>> The idea of a static predicate is for them to stand-in for proper set
>> constraints (I would have preferred the latter, but I was alone on that), so
>> they don't have anything to do with array bounds.
> 
> What do you mean by "proper set constraints"? [And how would they look?]
> Things like {x| x in {2**y where y in 0..15} }? (X in 1|2|4|8|16|..|32_768)

Certainly not an arbitrary constraint. The problem is with the 
operations, i.e. with substitutability. Constraining should not violate 
much of it and the user must known what gets broken. An arbitrary 
constraint breaks pretty much everything and you have no idea which 
operations still work. Ada's range constraint breaks a limited number of 
things and many of these breaks can be statically checked.

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

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

* Re: class wide iterable (and indexable)
@ 2019-01-29  7:45 Randy Brukardt
  2019-01-29 19:34 ` Niklas Holsti
  0 siblings, 1 reply; 76+ messages in thread
From: Randy Brukardt @ 2019-01-29  7:45 UTC (permalink / raw)


"Shark8" <onewingedshark@gmail.com> wrote in message
news:f4c1e192-9a24-40d1-abd1-233ef6087658@googlegroups.com...
> On Wednesday, January 23, 2019 at 3:47:43 PM UTC-7, Randy Brukardt wrote:
>> "Shark8" wrote in message
>> news:9eedf818-8bfb-465b-afe5-aa3fb0525948...
>> > Wouldn't this be a non-issue if we could Static_Predicate Array-types
>> > like
>> > so?
>> >
>> > Type Some_String is Array(Positive range <>) of Character
>> >  with Static-Predicate => Some_String'First = 1;
>>
>> The idea of a static predicate is for them to stand-in for proper set
>> constraints (I would have preferred the latter, but I was alone on that),
>> so
>> they don't have anything to do with array bounds.
>
> What do you mean by "proper set constraints"? [And how would they look?]
> Things like {x| x in {2**y where y in 0..15} }? (X in
> 1|2|4|8|16|..|32_768)

See AI05-0153-2. The idea was that there was a kind of constraint that
represented a set. I used "when" in the syntax to reflect a case statement
limb:

    subtype Odd is Natural when 1|3|5|7|9;

The main difference semantically from static predicates was that these
actually changed the value set, which eliminated (at least in my mind) the
oddities with 'First and 'Last that occur for predicates. Otherwise, their
pretty much the same (including the banning of arrays and slices to
eliminate discontiguous arrays).

I was pretty much a group of one with this idea, so the AI was never really
vetted. So don't trust it too much.

                       Randy.

[Sorry about breaking the thread, I got a bunch of header errors when 
attempting to send a reply.]



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

* Re: class wide iterable (and indexable)
  2019-01-29  7:45 Randy Brukardt
@ 2019-01-29 19:34 ` Niklas Holsti
  2019-01-29 20:26   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 76+ messages in thread
From: Niklas Holsti @ 2019-01-29 19:34 UTC (permalink / raw)


On 19-01-29 09:45 , Randy Brukardt wrote:
> "Shark8" <onewingedshark@gmail.com> wrote in message
> news:f4c1e192-9a24-40d1-abd1-233ef6087658@googlegroups.com...
>> On Wednesday, January 23, 2019 at 3:47:43 PM UTC-7, Randy Brukardt wrote:
>>> "Shark8" wrote in message
>>> news:9eedf818-8bfb-465b-afe5-aa3fb0525948...
>>>> Wouldn't this be a non-issue if we could Static_Predicate Array-types
>>>> like
>>>> so?
>>>>
>>>> Type Some_String is Array(Positive range <>) of Character
>>>>  with Static-Predicate => Some_String'First = 1;
>>>
>>> The idea of a static predicate is for them to stand-in for proper set
>>> constraints (I would have preferred the latter, but I was alone on that),
>>> so
>>> they don't have anything to do with array bounds.
>>
>> What do you mean by "proper set constraints"? [And how would they look?]
>> Things like {x| x in {2**y where y in 0..15} }? (X in
>> 1|2|4|8|16|..|32_768)
>
> See AI05-0153-2. The idea was that there was a kind of constraint that
> represented a set. I used "when" in the syntax to reflect a case statement
> limb:
>
>     subtype Odd is Natural when 1|3|5|7|9;
>
> The main difference semantically from static predicates was that these
> actually changed the value set, which eliminated (at least in my mind) the
> oddities with 'First and 'Last that occur for predicates. Otherwise, their
> pretty much the same (including the banning of arrays and slices to
> eliminate discontiguous arrays).

Another approach to the same (?) could be to allow enumerated types 
where the literals are integers, as in:

    type Odd is (1, 3, 5, 7, 9);  -- NOT current Ada!

This is no weirder than the current enumerated types where the literals 
are characters, as in the well-known example of Roman numbers.

And then -- hey presto! -- we connect to the thread about enumeration 
representations and gappy representations, where arrays and slices _are_ 
allowed ... so the same compiler machinery could be reused for "integer 
enumeration" types, no?

Of course one would have to be careful how (and if) the arithmetic 
operators are defined for "integer enumeration" types.

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

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

* Re: class wide iterable (and indexable)
  2019-01-29 19:34 ` Niklas Holsti
@ 2019-01-29 20:26   ` Dmitry A. Kazakov
  0 siblings, 0 replies; 76+ messages in thread
From: Dmitry A. Kazakov @ 2019-01-29 20:26 UTC (permalink / raw)


On 2019-01-29 20:34, Niklas Holsti wrote:

> Another approach to the same (?) could be to allow enumerated types 
> where the literals are integers, as in:
> 
>     type Odd is (1, 3, 5, 7, 9);  -- NOT current Ada!

What is the semantics of this? Is Odd'(3) = Odd'(1) + Odd'(1) + Odd'(1). No?

> Of course one would have to be careful how (and if) the arithmetic 
> operators are defined for "integer enumeration" types.

One should start with this question. What is the type structure one want 
to create. How many people need that kind of thing. Why language should 
support it.

A much easier approach is just not to bother. Simply provide 
user-defined literals, sane interface inheritance, reasonable statically 
enforced contracts, ADT in short. Leave the rest to the programmer.

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


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

end of thread, other threads:[~2019-01-29 20:26 UTC | newest]

Thread overview: 76+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-02 15:48 class wide iterable (and indexable) George Shapovalov
2019-01-02 17:39 ` Simon Wright
2019-01-02 18:11   ` George Shapovalov
2019-01-03  8:52     ` Simon Wright
2019-01-03  9:30       ` George Shapovalov
2019-01-03 16:45         ` Jeffrey R. Carter
2019-01-04  4:32       ` Shark8
2019-01-05  9:03         ` Randy Brukardt
2019-01-03 22:56     ` Randy Brukardt
2019-01-04  0:00       ` George Shapovalov
2019-01-04  8:43         ` Dmitry A. Kazakov
2019-01-04 12:20           ` George Shapovalov
2019-01-05 23:29             ` Jere
2019-01-05 23:50               ` Jere
2019-01-06  9:34                 ` George Shapovalov
2019-01-06 10:19                   ` Dmitry A. Kazakov
2019-01-06 11:30                     ` George Shapovalov
2019-01-06 12:45                       ` Dmitry A. Kazakov
2019-01-06 13:18                         ` George Shapovalov
2019-01-06 14:13                           ` Dmitry A. Kazakov
2019-01-06 16:33                             ` George Shapovalov
2019-01-06 18:29                               ` George Shapovalov
2019-01-06 20:32                                 ` Dmitry A. Kazakov
2019-01-06 21:47                                   ` George Shapovalov
2019-01-07  9:37                                     ` Niklas Holsti
2019-01-07 16:24                                       ` George Shapovalov
2019-01-06 20:18                               ` Dmitry A. Kazakov
2019-01-06 21:58                                 ` George Shapovalov
2019-01-07  8:28                                   ` Dmitry A. Kazakov
2019-01-05  9:21           ` Randy Brukardt
2019-01-05 10:07             ` Dmitry A. Kazakov
2019-01-05 18:17               ` George Shapovalov
2019-01-05 20:07                 ` Simon Wright
2019-01-05 20:41                   ` George Shapovalov
2019-01-07 21:07               ` Randy Brukardt
2019-01-08  9:51                 ` Dmitry A. Kazakov
2019-01-08 19:25                   ` Björn Lundin
2019-01-08 23:26                   ` Randy Brukardt
2019-01-09 17:06                     ` Dmitry A. Kazakov
2019-01-09 23:38                       ` Randy Brukardt
2019-01-10  8:53                         ` Dmitry A. Kazakov
2019-01-10 22:14                           ` Randy Brukardt
2019-01-11  9:09                             ` Dmitry A. Kazakov
2019-01-14 22:59                               ` Randy Brukardt
2019-01-15  9:34                                 ` Dmitry A. Kazakov
2019-01-18 15:48                                   ` Olivier Henley
2019-01-18 16:08                                     ` Dmitry A. Kazakov
2019-01-18 16:29                                       ` Olivier Henley
2019-01-18 16:54                                         ` Dmitry A. Kazakov
2019-01-18 17:31                                           ` Olivier Henley
2019-01-18 18:51                                             ` Shark8
2019-01-18 20:09                                             ` Dmitry A. Kazakov
2019-01-21 23:15                                     ` Randy Brukardt
2019-01-22  8:56                                       ` Dmitry A. Kazakov
2019-01-22 22:00                                         ` Randy Brukardt
2019-01-23  8:14                                           ` Dmitry A. Kazakov
2019-01-22 17:04                                       ` Jeffrey R. Carter
2019-01-22 22:02                                         ` Randy Brukardt
2019-01-23 18:00                                           ` Jeffrey R. Carter
2019-01-23 20:14                                           ` Shark8
2019-01-23 22:47                                             ` Randy Brukardt
2019-01-24 17:11                                               ` Dmitry A. Kazakov
2019-01-28 15:54                                               ` Shark8
2019-01-28 17:23                                                 ` Dmitry A. Kazakov
2019-01-08 18:32                 ` G. B.
2019-01-05 17:05             ` Jeffrey R. Carter
2019-01-05 20:18               ` Dmitry A. Kazakov
2019-01-05 21:09               ` Shark8
2019-01-06 10:11                 ` Jeffrey R. Carter
2019-01-05 20:46             ` Shark8
2019-01-06  9:43               ` Dmitry A. Kazakov
2019-01-26 22:11 ` George Shapovalov
2019-01-26 22:14   ` George Shapovalov
  -- strict thread matches above, loose matches on Subject: below --
2019-01-29  7:45 Randy Brukardt
2019-01-29 19:34 ` Niklas Holsti
2019-01-29 20:26   ` Dmitry A. Kazakov

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