experchange > ada

George Shapovalov (01-02-19, 05:48 PM)
Hello,

I apologize if something like this is a common thing, but search here or ongoogle 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 appropriatedata handling (say to let user select either dynamic, Ada.Containers.Vectors based, or fixed, based on plain arrays storage).

See here for working code:


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 aroundbase array..

Then common code could be kept in class-wide methods, using the new loop forms, like in:
Simon Wright (01-02-19, 07:39 PM)
George Shapovalov <gshapovalov> 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__rev ersible_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__ne xt__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 ...
George Shapovalov (01-02-19, 08:11 PM)
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 nowexact 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 suchcode 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..
Simon Wright (01-03-19, 10:52 AM)
George Shapovalov <gshapovalov> 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]
[2]
[3]
[4]
George Shapovalov (01-03-19, 11:30 AM)
> 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, butapparently this was not the majority opinion..

Thanks again for all the pointers!
George
Jeffrey R. Carter (01-03-19, 06:45 PM)
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.
Randy Brukardt (01-04-19, 12:56 AM)
"George Shapovalov" <gshapovalov> wrote in message
news:ab38
....
>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.
George Shapovalov (01-04-19, 02:00 AM)
> 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 tocorrespond 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 sortof
> 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 neededand 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 Icould 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? (atthe 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..
Shark8 (01-04-19, 06:32 AM)
On Thursday, January 3, 2019 at 1:52:50 AM UTC-7, Simon Wright wrote:
[..]
> 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 --
Dmitry A. Kazakov (01-04-19, 10:43 AM)
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.
George Shapovalov (01-04-19, 02:20 PM)
> 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, thanksfor 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 theywere intended - to clarify further comments). Especially compared to glorified macros in the form of templates in C++ or similar. Having had to fightthose, it is easy to appreciate clear (and much more verifiable) form of generics in Ada after that..

> 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
Randy Brukardt (01-05-19, 11:03 AM)
"Shark8" <onewingedshark> wrote in message
news:aeea
> On Thursday, January 3, 2019 at 1:52:50 AM UTC-7, Simon Wright wrote:
> True; but the Automatic Instantiation AI would relieve a lot of the hassle
> here --
>


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.
Randy Brukardt (01-05-19, 11:21 AM)
"Dmitry A. Kazakov" <mailbox> wrote in message
news:tqs1
....
> 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.
Dmitry A. Kazakov (01-05-19, 12:07 PM)
On 2019-01-05 10:21, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox> wrote in message
> news:tqs1
> ...
>> 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.

> 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.
Jeffrey R. Carter (01-05-19, 07:05 PM)
On 1/5/19 10:21 AM, Randy Brukardt wrote:
[..]
> 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.

Similar Threads