Version 1.3 of ai12s/ai12-0435-1.txt

Unformatted version of ai12s/ai12-0435-1.txt version 1.3
Other versions for file ai12s/ai12-0435-1.txt

!standard 4.10(6/5)          21-06-07 AI12-0435-1/03
!standard 4.10(15/5)
!standard 4.10(26/5)
!standard 13.13.2(38/4)
!class Amendment 21-05-29
!status Amendment 1-2012 21-06-07
!status ARG Approved 12-0-2 21-06-03
!status work item 21-05-29
!status received 21-05-29
!priority Low
!difficulty Easy
!subject Fixups from WG 9 Issue #143 - Image and streams
!summary
(1) Exclude null extensions from the Implementation Advice about type extensions.
(2) Define the subtype of the parameters to the default Put_Image implementations similarly to that for the stream-oriented attributes.
(3) The subprogram specified for Put_Image cannot be abstract.
(4) Stream-oriented attributes are implicitly composed.
!problem
(1) It seems desirable that if we have a tagged specific noninterface type T1 and a specific type T2 which is a proper descendant of T1 (i.e., a descendant of T1 other than T1 itself), and if T2 is "the same" as T1 ("the same" meaning that no new components are defined nor Put_Image redefined for T2), then for any value X of T2 it should be the case that T2'Image (X) = T1'Image (T1 (X)).
This is not true when T2 is a null extension of T1. If T1'Image (X) = "(Some Image Text)", then (according to the implementation advice) T2'Image (T2 (X)) should equal something like "((Some Image Text) with NULL)".
(2) Are rules for determining the parameter subtypes for T'Put_Image procedures sufficiently well-defined?
For example, is the "others" aggregate in the following code legal?
type T is array (1 .. 10) of Integer; -- first subtype is constrained
procedure Foo (Buff : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class) is begin
T'Put_Image (Buff, (others => 123)); -- legal?
end Foo;
(3) For streams, we have a rule The subprogram name given in such an attribute_definition_clause or aspect_specification shall statically denote a subprogram that is not an abstract subprogram.
We don't have an similar rule for Put_Image. Since we want the image of any type (including abstract types) to be well-defined, this seems to be an oversight.
(4) we have rules in 13.1.1 and 12.5.1 that apply to aspects that are "implicitly composed", but we have no explicit statements anywhere in the manual that any particular aspects are "implicitly composed". This should be stated explicitly for Put_Image and for the aspects corresponding to the stream-oriented attributes.
!proposal
(See Summary.)
!wording
(1) Modify 4.10(6/5):
For an untagged derived type{, or a null extension}, the default implementation of T'Put_Image invokes the Put_Image for its parent type on a conversion of the parameter of type T to the parent type.
Modify 4.10(15/5):
For a {nonnull} type extension, the default implementation of T'Put_Image depends on whether there exists a noninterface ancestor of T (other than T itself) for which the Put_Image aspect has been directly specified. If so, then T'Put_Image will generate an image based on extension aggregate syntax where the ancestor type of the extension aggregate is the nearest ancestor type whose Put_Image aspect has been specified. If no such ancestor exists, then the default implementation of T'Put_Image is the same as described below for a nonderived record type.
(2) and (3) Add after 4.10(26/5):
In the parameter_and_result_profile for the default implementation of Put_Image, the subtype of the Arg parameter is the base subtype of T if T is a scalar type, and the first subtype otherwise. For an aspect_specification or attribute_definition_clause specifying Put_Image, the subprogram name shall denote a nonabstract procedure whose second parameter is either of the first subtype of T, or as an option when T is scalar, the base subtype of T.
(4) Modify 13.13.2(38/4):
The stream-oriented attributes may be specified for any type via an attribute_definition_clause. Redundant[Alternatively, each of the specific stream-oriented attributes may be specified using an aspect_specification on any type_declaration, with the aspect name being the corresponding attribute name.] Each of the class-wide stream-oriented attributes may be specified using an aspect_specification for a tagged type T using the name of the stream-oriented attribute followed by 'Class; such class-wide aspects do not apply to other descendants of T. {If not directly specified, a default implementation of a stream-oriented attribute is implicitly composed for a nonlimited type, and for certain limited types, as defined above.}
!discussion
(1) Its unclear to the Editor whether this is really a principle that we want to support. OTOH, he has consistently objected to treating null extensions specially and has lost that argument consistently.
(2) We copy the definition of stream-oriented attributes for Put_Image.
(3) We never want Put_Image to be uncallable, so abstract routines should be banned. There's no problem with null procedures (even though they don't seem very useful in this context), so we allow them.
(4) 4.10(4/5) states that Put_Image is implicitly composed. We don't have such wording for stream-oriented attributes, though.
!corrigendum 4.10(0)
Insert new clause:
See the conflict file for the changes.
!corrigendum 13.13.2(38/4)
Replace the paragraph:
The stream-oriented attributes may be specified for any type via an attribute_definition_clause. Alternatively, each of the specific stream-oriented attributes may be specified using an aspect_specification on any type_declaration, with the aspect name being the corresponding attribute name. Each of the class-wide stream-oriented attributes may be specified using an aspect_specification for a tagged type T using the name of the stream-oriented attribute followed by 'Class; such class-wide aspects do not apply to other descendants of T.
by:
The stream-oriented attributes may be specified for any type via an attribute_definition_clause. Alternatively, each of the specific stream-oriented attributes may be specified using an aspect_specification on any type_declaration, with the aspect name being the corresponding attribute name. Each of the class-wide stream-oriented attributes may be specified using an aspect_specification for a tagged type T using the name of the stream-oriented attribute followed by 'Class; such class-wide aspects do not apply to other descendants of T. If not directly specified, a default implementation of a stream-oriented attribute is implicitly composed for a nonlimited type, and for certain limited types, as defined above.
!ASIS
No ASIS effect.
!ACATS test
ACATS B-Tests should be constructed to test the subtypes of the parameters of Put_Image and to check that abstract subprograms cannot be specified.
ACATS C-Tests should be constructed to check that null extensions do not affect the image.
!appendix

From WG 9 review issue #143 - Steve Baird

It seems desirable that if we have a tagged specific noninterface type
T1 and a specific type T2 which is a proper descendant of T1 (i.e., a
descendant of T1 other than T1 itself), and if T2 is "the same" as T1
("the same" in a sense I'll describe in a moment), then for any value
X of T2 it should be the case that T2'Image (X) = T1'Image (T1 (X)).

When I say that T1 and T2 are "the same", I mean that neither T2 nor any
other proper descendant of T1 that is also an ancestor of T2 either

    defines any new components (including discriminants); or
    has an explicitly-specified Put_Image aspect.

This seems to generally be true, but (unfortunately) not always.
Consider the case where a type T1 has a user-defined Put_Image aspect
and a type T2 is a null extension of T1, declared as
type T2 is new T1 with null record;

The implementation advice about how to handle this case does not have
a special case for null extension (or a null extension of a null extension,
etc.). So if T1'Image (X) = "(Some Image Text)", then (according to that
advice) T2'Image (T2 (X)) should equal something like
"((Some Image Text) with NULL)".
That's not what we want.

===

Are rules for determining the parameter subtypes for T'Put_Image
procedures sufficiently well-defined? [Tuck raised this question.]

For example, is the "others" aggregate in the following code legal?

type T is array (1 .. 10) of Integer; -- first subtype is constrained

procedure Foo
(Buff : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class) is
begin
T'Put_Image (Buff, (others => 123)); -- legal?
end Foo;

===

For streams, we have a rule
The subprogram name given in such an attribute_definition_clause or
aspect_specification shall statically denote a subprogram that is not
an abstract subprogram.

The word "abstract" does not appear anywhere in 4.10; that seems like a
problem. We want to prohibit something like

type T is tagged record ... end record with Put_Image => Foo;
procedure Foo () is abstract;

Assuming such a rule, would a (redundant) note be useful pointing out
that Some_Abstract_Type'Put_Image is never an abstract procedure?

===

On a related note, we have rules in 8.6 that apply to aspects that are
"implicitly composed", but we have no explicit statements anywhere in
the manual that any particular aspects are "implicitly composed".
This should be stated explicitly for Put_Image and for the
aspects corresponding to the stream-oriented attributes.

[Tucker Taft replied:]

As far as null extensions, I would agree with Steve we should suppress them.
So I would suggest:

Modify 4.10(6/5):

   For an untagged derived type{, or a null extension}, the default 
   implementation of T'Put_Image invokes the Put_Image for its parent type
   on a conversion of the parameter of type T to the parent type.

Modify 4.10(15/5):

   For a {nonnull} type extension, the default implementation of T'Put_Image 
   depends on whether there exists a noninterface ancestor of T (other than T
   itself) for which the Put_Image aspect has been directly specified. If so,
   then T'Put_Image will generate an image based on extension aggregate syntax
   where the ancestor type of the extension aggregate is the nearest ancestor
   type whose Put_Image aspect has been specified. If no such ancestor exists,
   then the default implementation of T'Put_Image is the same as described
   below for a nonderived record type.

---

As far as the subtype of the parameters, for stream attributes we have:
13.13.2(50/3-51/3):

   In the parameter_and_result_profiles for the default implementations of the 
   stream-oriented attributes, the subtype of the Item parameter is the base 
   subtype of T if T is a scalar type, and the first subtype otherwise. The
   same rule applies to the result of the Input attribute.

   For an attribute_definition_clause specifying one of these attributes, the 
   subtype of the Item parameter shall be the first subtype or the base
   subtype if scalar, and the first subtype if not scalar. The same rule
   applies to the result of the Input function.

We presumably need something analogous for Put_Image. As far as the use of 
"abstract" procedures for Put_Image, I agree we want to disallow them. All
types have Put_Image, including all abstract types, and we want to be able to
presume it is a non-abstract procedure in generics, etc. And the implicitly
composed Put_Image for a type extension of an abstract type will invoke the
parent's operation, so again, we want to be sure it is nonabstract. Hence,
I recommend we add a paragraph to specify both the parameter subtype, and the
requirement to be nonabstract:

Add after 4.10(26/5):

  In the parameter_and_result_profile for the default implementation of 
  Put_Image, the subtype of the Arg parameter is the base subtype of T if T
  is a scalar type, and the first subtype otherwise. For an 
  aspect_specification or attribute_definition_clause specifying Put_Image,
  the subprogram name shall denote a nonabstract procedure whose second
  parameter is either of the first subtype of T, or as an option when T
  is scalar, the base subtype of T.

---

As far as "implicitly composed" we do say something in 4.10(4/5) about 
Put_Image, but there is nothing about how the stream attributes are
implicitly composed. So I would suggest:

Modify 13.13.2(9.1/5):

  {For derived types, the default implementations of the Write and Read 
  attributes are not inherited, but are rather implicitly composed.} For
  type extensions, the Write or Read attribute for the parent type is
  called, followed by the Write or Read attribute of each component of the
  extension part, in canonical order. For a limited type extension, if the
  attribute of the parent type or any progenitor type of T is available
  anywhere within the immediate scope of T, and the attribute of the parent
  type or the type of any of the extension components is not available at
  the freezing point of T, then the attribute of T shall be directly
  specified. For untagged derived types, the Write (resp. Read) attribute
  invokes the corresponding attribute of the parent type, if the attribute
  is available for the parent type.

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

From: Tucker Taft
Sent: Sunday, May 30, 2021  9:00 AM

Randy recently posted AIs for our upcoming review of WG9 comments.  He asked
me to comment on the Put_Image/Stream attribute fixups.  Here are two of the
four issues for which I had a comment:

>(1) Modify 4.10(6/5):
>   For an untagged derived type{, or a null extension}, the default
>   implementation of T'Put_Image invokes the Put_Image for its parent type
>   on a conversion of the parameter of type T to the parent type.
>Modify 4.10(15/5):
>   For a {nonnull} type extension, the default implementation of T'Put_Image
>   depends on whether there exists a noninterface ancestor of T (other than T
>   itself) for which the Put_Image aspect has been directly specified. If so,
>   then T'Put_Image will generate an image based on extension aggregate syntax
>   where the ancestor type of the extension aggregate is the nearest ancestor
>   type whose Put_Image aspect has been specified. If no such ancestor exists,
>   then the default implementation of T'Put_Image is the same as described
>   below for a nonderived record type.
>...
>(4) Modify 13.13.2(9.1/5):
>  {For derived types, the default implementations of the Write and Read
>  attributes are not inherited, but are rather implicitly composed.} For
>  type extensions, the Write or Read attribute for the parent type is
>  called, followed by the Write or Read attribute of each component of the
>  extension part, in canonical order. For a limited type extension, if the
>  attribute of the parent type or any progenitor type of T is available
>  anywhere within the immediate scope of T, and the attribute of the parent
>  type or the type of any of the extension components is not available at
>  the freezing point of T, then the attribute of T shall be directly
>  specified. For untagged derived types, the Write (resp. Read) attribute
>  invokes the corresponding attribute of the parent type, if the attribute
>  is available for the parent type.
>[Editor's complaint: This only covers Read and Write. What about Input
>and Output, and the class-wide versions of all of these?? I would have expected
>a general statement at the top of 13.13.2 instead of this.]

I think we could instead put a general statement at the end of paragraph 
13.13.2(38/4):

Modify 13.13.2(38/4):
The stream-oriented attributes may be specified for any type via an 
attribute_definition_clause. [Alternatively, each of the specific 
stream-oriented attributes may be specified using an aspect_specification
on any type_declaration, with the aspect name being the corresponding
attribute name.] Each of the class-wide stream-oriented attributes may be
specified using an aspect_specification for a tagged type T using the name
of the stream-oriented attribute followed by 'Class; such class-wide aspects
do not apply to other descendants of T. {If not directly specified, a default
implementation of a stream-oriented attribute is implicitly composed for a
nonlimited type, and for certain limited types, as defined above.}
 
>!discussion
>(1) It's unclear to the Editor whether this is really a principle that we
>want to support. OTOH, he has consistently objected to treating null
>extensions specially and has lost that argument consistently.

As far as the proposal about null extensions identified as issue (1) above,
here is the logic:  If you have a tagged type T1 and its null extension T2,
the default implementation of the Put_Image attributes for T1 and T2 will be
identical, since they will each be displayed as a record aggregate, and they
have the same number of components.  Similarly, if the parent of T1 (or some
more remote ancestor) has a Put_Image attribute specified (let's call it T0),
then the implicitly composed Put_Image attributes for T1 and T2 will again be
identical, since they have the same set of additional components relative to
T0.  So it makes sense that in general the implicitly composed Put_Image
attribute for T2 should be the same as whatever T1'Put_Image produces. Another
reason for null extensions to directly reuse the Put_Image of their parent is
that a standard idiom for making a tagged type exported by a generic
instantiation directly visible, is by using a null extension, so it would be
annoying to instantiate a generic which provides a Put_Image, and then
suddenly find a "(... with Null)" wrapper appearing around all of the 'Image
results.  Finally, we have gone out of our way to make (essentially) all
primitive operations of a type be inherited "as is" by a null extension,
including functions with controlling results, which would normally require
overriding.  So "inheriting" Put_Image (via implicit composition) as is,
makes sense as well.
...

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

From: Randy Brukardt
Sent: Wednesday, June 2, 2021  9:43 PM

>>	!discussion
>>	(1) It's unclear to the Editor whether this is really a principle that we
>>	want to support. OTOH, he has consistently objected to treating null
>>	extensions specially and has lost that argument consistently.

>	As far as the proposal about null extensions identified as issue (1) above,
> here is the logic:  If you have a tagged type T1 and its null extension T2, the
> default implementation of the Put_Image attributes for T1 and T2 will be
> identical, since they will each be displayed as a record aggregate, and they
> have the same number of components.  Similarly, if the parent of T1 (or some
> more remote ancestor) has a Put_Image attribute specified (let's call it T0), 
> then the implicitly composed Put_Image attributes for T1 and T2 will again be
> identical, since they have the same set of additional components relative to
> T0.  So it makes sense that in general the implicitly composed Put_Image 
> attribute for T2 should be the same as whatever T1'Put_Image produces.

This seems like justifying a glitch by doubling down on the glitch: I see no
reason that T1 and T2 necessarily have the same Image, by default or any other
reason. Perhaps the advice makes that the case, but that would seem to be
accidental rather than any sort of intentional result.

> Another reason for null extensions to directly reuse the Put_Image of their 
> parent is that a standard idiom for making a tagged type exported by a 
> generic instantiation directly visible, is by using a null extension, so
> it would be annoying to instantiate a generic which provides a Put_Image,
> and then suddenly find a "(... with Null)" wrapper appearing around all of
> the 'Image results.

This "idiom" is evil, and needs to be replaced by something (anything!) else.
One *never* wants to introduce a type unless one really needs it to be
different in an apples-and-oranges sense. If the Image was to increase
encouragement to avoid this idiom (and perhaps provide a replacement, as in
deferred AI12-0229-1), that would seem to be a good thing!

> Finally, we have gone out of our way to make (essentially) all primitive 
> operations of a type be inherited "as is" by a null extension, including
> functions with controlling results, which would normally require
> overriding. So "inheriting" Put_Image (via implicit composition) as is, 
> makes sense as well.

This is also evil, at least for the likely uses that I have for null
extensions. Most likely, a null extension is just a placeholder for a type
that eventually will gain extension components (it's unlikely that one can
usefully replace operations of a type without some additional/different data).
In this case, getting a clean compiler for a null extension tells one nothing
about the requirements on the type in the actual program; one has to declare
dummy components in order to do that. Which brings up all of the problems of
dummy components. I would not object to extending this capability to other
extensions (those with extension components with appropriate defaults), as
that would mitigate the problem -- but of course no extension to Image would
make sense in that case. (AI12-0083-1, also deferred, proposed something on
this line to make classic mix-in generics more general.)

Anyway, as I stated at the outset, I've consistently lost this argument, so
I'll go crawl back under my rock. :-)

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

From: Richard Wai
Sent: Wednesday, June 2, 2021  11:10 PM

Since I pretty strongly agree with what Tuck said generally, I will just chime 
in to say that, from a higher level engineering or design perspective, you can 
(and I often will) make the case for declaring a new type that is exactly the 
"same" as an existing type. If your real purpose in the use of a type is to 
assert that some data is different than some other data with the exact same 
representation, then you'd want separate types. Of course we all know the 
classic example of measurement units and the like, but I don't see why this 
couldn't also apply to (tagged) record types.

As a crude example, say I have:

type Contact_Information record
   record
      Name: Name_String;
      Address: Address_String;
      Email: Email_String;
   end record;

procedure Send_Email (Contact: in Contact_Information; Content: in String);

In my application, I store contact information for businesses and individuals. 
I can know, as a matter of design, that I need to treat businesses and 
individuals very differently, but I may need to do various actions on their 
contact info, such as sending an automated email, which might be essentially 
the same between businesses and individuals.

In this case, it makes perfect sense to define both type Individual_Contact 
and type Business_Contact as null extensions of Contact_Information. That way
I can be sure that nothing that expects a business contact will get a
individual contact (unless explicitly converted). I'd of course not get that
same protection if I was merely using subtypes.

Additionally, I might (or might not) want to make selective overrides to the
operations of the type, while inheriting the rest (such as Put_Image).

So I'd disagree with your comment that "it's unlikely that one can usefully
replace operations of a type without some additional/different data)" . In 
this example, merely knowing that the contact is for a business rather than
a client determines how I will interpret or use the components of the record.
Of 

I do agree with you that the generic instantiation idiom is probably evil!

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

From: Tucker Taft
Sent: Thursday, June 3, 2021  7:40 AM

>>      !discussion
>>      (1) It's unclear to the Editor whether this is really a principle
>>      that we want to support. OTOH, he has consistently objected to
>>      treating null extensions specially and has lost that argument
>>      consistently.

>       As far as the proposal about null extensions identified as issue (1)
>       above, here is the logic: ...
 
>Anyway, as I stated at the outset, I've consistently lost this argument, so
>I'll go crawl back under my rock. :-)

In most cases I find that I understand your arguments when you feel strongly 
about something, but I will admit I do not understand your strong objection 
to the use of "null extensions" as the way to create a new tagged type that 
is "nearly the same" as some existing type (particularly a type produced as a 
result of a generic instantiation).  Of course if you don't like them, you
don't have to use them, but I have many examples from my own experience where
it seems to be the right thing to do, and does not seem to be "evil" from a 
software engineering point of view.   So presuming other folks might have 
similar experiences with how it is appropriate to use null extensions, we 
should have a consistent set of language principles about null extensions, 
and I believe the proposed fix provides that consistency.

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

From: Randy Brukardt
Sent: Thursday, June 3, 2021  11:22 PM

>In most cases I find that I understand your arguments when you feel strongly
>about something, but I will admit I do not understand your strong objection 
>to the use of "null extensions" as the way to create a new tagged type that
>is "nearly the same" as some existing type (particularly a type produced as
>a result of a generic instantiation). Of course if you don't like them, you
>don't have to use them, but I have many examples from my own experience
>where it seems to be the right thing to do, and does not seem to be "evil"
>from a software engineering point of view.

It not about not liking "null extensions"; of course one has to use them 
often. The problem is that this special semantics substantially interferes 
with the sort of incremental development that I (strongly) prefer. I 
explained this in more detail in one of my responses to AI12-0083-1, so let
me steal from that:

   This is my problem with the existing null extension rule; future maintenance
   often adds extension components, and when that happens, all of a sudden you
   have to write a bunch more routines. That's especially annoying given the way
   that I typically create extensions (write a null extension, override all of
   the routines that will need overriding, with TBD bodies [raise Program_Error
   or the like], compile to make sure everything is correct, then start
   implementing the routines -- at which point extension components get added
   and all of the work to check that everything is overridden has to thrown out
   the window and redone).

"All of the routines that will need overriding" include any abstract 
ancestors, as well as routines that "obviously" will need new versions. This 
step is very time-consuming for a complex set of types (it takes a day or more
for the Claw Builder's types), and rather violates the principles of 
incremental development that I've always used (long before that was a
"thing"). (That is, always have a testable version for every few hours of
work.) Having to redo it halfway through development is very frustrating, 
especially as I tend to use a lot of functions returning a tagged type.

If there was a way to let a regular extension use this same machinery (as 
suggested in AI12-0083-1), this objection would be mitigated quite a bit, as
most extension components have reasonable defaults that could be used. It
wouldn't always work, but that's OK (can't expect the compiler to write your
program for you in every instance!)

>So presuming other folks might have similar experiences with how it is
>appropriate to use null extensions, we should have a consistent set of
>language principles about null extensions, and I believe the proposed fix
>provides that consistency.

The problem isn't about using null extensions, the problem is that one can't 
easily change them into a regular extension when that (inevitably in my
experience) needs to occur. Doing so breaks a substantial amount of the code 
already written, and forces overriding a substantial percentage of the 
routines.

I rarely see a type that has no extension components, since it is unlikely 
that one can write different operations using only the existing components.
It can happen, but not very often. I realize that others use these things 
differently, specifically finding some value in interface inheritance, so they
might see null extensions more frequently, but it still seems rare to me.
(Introducing otherwise unneeded types just for visibility purposes will always
be evil to me, however; either use a "use all" for such a thing or lobby for
a proper language fix and write out the longer names until then.)

Anyway, as I said previously, I have zero expectation of winning this 
argument -- ever -- but I detest the difference between null extensions and 
other extensions (and the mix-in problems raised in AI12-0083-1 illustrate 
the issues as well).

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

From: Tucker Taft
Sent: Friday, June 4, 2021  7:10 AM

Clearly the narrow issue of Put_Image is now overtaken by events.  But in the
larger issue, I have no argument with giving more extensions the advantages of
null extensions when it comes to automatically providing implementations of 
functions with controlling results.  But at this point we clearly aren't going 
to *remove* the advantages that null extensions provide, and even if we give 
more extensions the advantages of null extensions, the proposed (now approved)
change to Put_Image would still make sense in my view.

As far as the incremental development issue, I would suggest you use a private 
extension rather than a visible null extension in your initial extension, if 
you are having the trouble you describe.

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

From: Bob Duff
Sent: Friday, June 4, 2021  8:22 AM

> As far as the incremental development issue, I would suggest you use a 
> private extension rather than a visible null extension in your initial 
> extension, if you are having the trouble you describe.

Doesn't Randy also need to put in a dummy component ("TBD: Boolean := raise 
Program_Error;" or some such)?

In any case, he can't fully write the required overridings until he's decided
what components he wants to have.

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

From: Randy Brukardt
Sent: Friday, June 4, 2021 10:21 PM

...
> Doesn't Randy also need to put in a dummy component ("TBD: 
> Boolean := raise Program_Error;" or some such)?
> 
> In any case, he can't fully write the required overridings until he's 
> decided what components he wants to have.

True enough, but my primary goal is always to keep the code compilable as much
as possible. That allows detecting errors in code I just wrote before I forget
the details of what it is supposed to do. The sorts of unfinished sentences
that turn up in AIs periodically appear in my code, too, and finishing them
requires having  an idea of what they are supposed to be.

It's almost always the case that I have to add additional overridings after 
the initial bunch, but those don't interfere with compilation like the initial
requirement to override abstract routines (and functions if it isn't a null
exclusion) does. In a system like the Claw Builder, I typically have a root
abstract type that everything else derives from, and that type provides
default implementations of some routines where that makes sense -- but the
others are abstract. This is admittedly a problem where every solution is
lousy -- one could avoid the compilation issues by having useless default
versions, but then the possibility of forgetting to implement something
critical would probably cause as much trouble. One gets similar problems
using variants and case statements in Ada, as the completeness checks
provide the same benefits and costs. I just hate having to do it twice
because of the null extension differences.

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

Questions? Ask the ACAA Technical Agent