Version 1.2 of ai05s/ai05-0023-1.txt

Unformatted version of ai05s/ai05-0023-1.txt version 1.2
Other versions for file ai05s/ai05-0023-1.txt

!standard 13.13.2(9/2)          07-04-05 AI05-0023-1/02
!class binding interpretation 06-11-13
!status work item 06-11-13
!status received 06-06-27
!priority Medium
!difficulty Hard
!qualifier Omission
!subject 'Read on records with variant parts
!summary
Compilers should not violate the finalization rules when creating 'Read.
!question
AI-195 and the section on 'Read seems to have a small hole in it when it comes to discriminant records with default discriminants and variant parts.
Consider for example:
type Customer_Description( Is_Company : Boolean := True ) is record case Is_Company is when True => Foo : Integer := 0; Bar : Integer := 0; Company_Name : Some_Controlled_Type; when False => Persons_Name : Some_Other_Controlled_Type; end case; end record;
Suppose we do a 'Read on an unconstrained object OBJ of type Customer_Description, whose Is_Company discriminant is currently TRUE. We read the discriminant, and the discriminant changes to FALSE. What happens to the Company_Name and Persons_Name fields, and when?
Can an anonymous object be used? If it is, is Initialize called on the controlled components? Must it be called? Or is this case more like an aggregate?
!recommendation
(See Summary.)
!wording
Add after 13.13.2(9/2)
If T is a discriminated type and its discriminants have defaults then S'Read first reads the discriminants from the stream without modifying Item. S'Read then creates an object of type T constrained by these discriminants. The Read attribute for each non-discriminant component of this object (not of Item) is then called in canonical order as described above. Finally, the value of this object is converted to the subtype of Item and is assigned to Item. Normal default initialization and finalization take place for this object.
In 13.13.2(27/2) replace
S'Input then creates an object...
with
S'Input then creates an object of type T...
Append to the end of 13.13.2(27/2)
If T has discriminants, then this object is constrained if and only if T has discriminants without defaults (that is, if and only if discriminants were read from the stream).
Add after 13.13.2(38)
Implementation Permissions
If T is a discriminated type and its discriminants have defaults then in some cases an execution of the default implementation of S'Read is not required to create an object of type T. The discriminant values that are read in may be checked against the corresponding discriminant values of Item. If they are equal, then no object of type T need be created and Item may be used instead. If they are not equal and Item is a constrained variable, then Constraint_Error may be raised at that point, before any further values are read from the stream and before the object of type T is created.
If T is a discriminated type and its discriminants have defaults and if an execution of the default implementation of S'Input will, at the point of its call to S'Read, execute the default implementation of S'Read, then the two executions are allowed to proceed as if the discriminants of T did not have defaults. This allows the combined executions of S'Input and S'Read to create one object of type T instead of two. If this option is exercised, then
- The discriminants are read from the stream by S'Input, not S'Read. - S'Input declares an object of type T constrained by
the discriminants read from the stream, not an unconstrained object.
- The discriminant values which S'Read would normally have read from
the stream are read from Item instead.
- The permissions of the preceding paragraph then apply and no object
of type T need be created by the execution of S'Read.
Questions: 1) When we say that "the value of this object ... is assigned to Item",
does it need to be explicitly stated that this is an assignment operation? Does the list of assignment operations in 5.2(3) need to be updated? I think not.
2) Does it need to be stated more explicitly that the permission to treat a
type with defaults as though it does not have defaults only applies in the case where S'Input calls S'Read and does not apply in the case where some other caller calls S'Read?
!discussion
This problem applies to all depends-on-discriminant components with non-trivial finalization.
--!corrigendum A.18.2(239/2)
!ACATS test
!appendix

!topic 'Read on records with variant parts
!reference RM05 13.13.2, AI95-195
!from Adam Beneschan 06-06-27
!discussion

In looking into a test case posted on comp.lang.ada, I've found that
AI-195 and the section on 'Read seems to have a small hole in it when
it comes to discriminant records with default discriminants and
variant parts.  I noticed that the word "variant" does not appear at
all in the AI-195 text (including discussions, e-mail, etc.)

Consider for example:

   type Customer_Description( Is_Company : Boolean := True ) is record
      case Is_Company Is
         when  True   =>
            Foo                 : Integer := 0;       
            Bar                 : Integer := 0;       
            Company_Name        : Some_Controlled_Type;
         when  False  =>
            Persons_Name        : Some_Other_Controlled_Type;
      end case;
   end record;

Suppose we do a 'Read on an unconstrained object OBJ of type
Customer_Description, whose Is_Company discriminant is currently TRUE.
We read the discriminant, and the discriminant changes to FALSE.  What
happens to the Company_Name and Persons_Name fields, and when?  

AI-195 suggests that when a record (not necessarily a variant record)
has discriminants, then the model requires the implementation to
create an anonymous object.  This will work; the implementation reads
the discriminants into an anonymous object, initializes the anonymous
object, then (perhaps) performs an assignment to copy the anonymous
object to OBJ, which requires OBJ to be finalized first; then 'Read on
the components can be performed directly into OBJ.  This will work
fine.  

However, the language about the anonymous object didn't make it into
the RM.  13.13.2(55/2) says only, as an Implementation Requirement,
"If Constraint_Error is raised during a call to Read because of
failure of one of the above checks, the implementation must ensure
that the discriminants of the actual parameter of Read are not
modified".  Unless there's some other part of the RM I've missed, this
appears to make it legal to, say, copy the discriminants into
temporary buffer, read the new discriminants directly into OBJ, and
set up exception-handling code that copies the previous discriminants
back to OBJ if necessary.  This will be a disaster, though, since it
will leave garbage in Company_Name or Persons_Name and will cause
problems as soon as a user-defined 'Read on the component tries to
finalize it.

This may be just a small nitpick (like lots of my contributions);
perhaps it should be "just obvious" that the implementation is
supposed to do it right.  But my impression is that there's a hole in
the RM's logic that needs plugging; particularly because of 13.13.2(9)
in the RM and AARM that seems to imply that a discriminant with a
default is simply treated like any other component by 'Read.

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

From: Randy Brukardt
Date: Tuesday, June 27, 2006  1:45 PM

> In looking into a test case posted on comp.lang.ada, I've found that
> AI-195 and the section on 'Read seems to have a small hole in it when
> it comes to discriminant records with default discriminants and
> variant parts.  I noticed that the word "variant" does not appear at
> all in the AI-195 text (including discussions, e-mail, etc.)

That's not surprising; the same issues occur for any
depends-on-a-discriminant component, whether that is by a variant or an
array constraint or whatever. There is rarely a reason to treat variants
specially.

...
> However, the language about the anonymous object didn't make it into
> the RM.  13.13.2(55/2) says only, as an Implementation Requirement,
> "If Constraint_Error is raised during a call to Read because of
> failure of one of the above checks, the implementation must ensure
> that the discriminants of the actual parameter of Read are not
> modified".  Unless there's some other part of the RM I've missed, this
> appears to make it legal to, say, copy the discriminants into
> temporary buffer, read the new discriminants directly into OBJ, and
> set up exception-handling code that copies the previous discriminants
> back to OBJ if necessary.  This will be a disaster, though, since it
> will leave garbage in Company_Name or Persons_Name and will cause
> problems as soon as a user-defined 'Read on the component tries to
> finalize it.
>
> This may be just a small nitpick (like lots of my contributions);
> perhaps it should be "just obvious" that the implementation is
> supposed to do it right.  But my impression is that there's a hole in
> the RM's logic that needs plugging; particularly because of 13.13.2(9)
> in the RM and AARM that seems to imply that a discriminant with a
> default is simply treated like any other component by 'Read.

Well, I guess I don't see a problem. The RM only gives a permission for
erroneous behavior in  very specific cases. I don't see that any of those
cases applies here (a well-defined Read of an entire record). For instance,
there's nothing abnormal because there is no exception. An implementation
that leads to disaster (that is, erroneous execution) is just wrong in the
absence of a specific rule allowing erroneous execution. The compiler in the
original question had a bug in an obscure case, and that's about all there
is to say.

Certainly the stream wording isn't the best wording ever, but messing with
it seems to lead to new problems. Perhaps an AARM note about the anonymous
objects as described in AI-195 would be a good idea, but that is about as
far as I think we should go.

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

From: Adam Beneschan
Date: Friday, July 7, 2006  8:23 PM

On second thought, it's probably not necessary to create an entire
anonymous object.  If just the discriminants are read into a temporary
buffer(s), then after all the discriminants are read in, the object
being 'Read can be finalized, the discriminants can be copied in, and
the object can be re-initialized with the new discriminants.

It still feels to me like something is missing, however.  It's pretty
clear to me that, when you do a 'Read on a record of type T that has
discriminants with defaults, and there are components of T that depend
on the discriminants, then *some* object of type T has to be
initialized (in the sense of 7.6) immediately after the discriminants
are read, and before any other components are read from the stream.
Suppose you have a record type like this:

    type Rec (N : My_Int_Type := 0) is record
        Component1 : Controlled_Type_1;
        Component2 : Controlled_Type_2;
        case N is
            ...  -- assume some controlled types or arrays whose
                 -- bounds depend on N are in here
        end case;
    end record;

Suppose also that user-defined 'Read routines were present for
My_Int_Type, Controlled_Type_1, and Controlled_Type_2, but not for
Rec; and that Initialize routines were defined for Controlled_Type_1
and _2 that set some global flags.  Now we do Rec'Read on some object.
I maintain that, if the user-defined 'Read routines checked the global
flags, the 'Read routine on My_Int_Type would always find that the
initialization flags were clear, and the 'Read routines on
Controlled_Type_1 and Controlled_Type_2 would always find that the
flags were set, because *some* object of type Rec has to be
initialized after N is read (in order to get the components in the
variant part initialized correctly), and this initialization would
have to call the user-defined Initialize routine for Controlled_Type_1
and _2.  In fact, I'd say this is so definitely true that an ACATS
test could be written that tests this.  

Would you agree with this?

Is this behavior implied by the language?  

Suppose that there were no components of Rec that depended on N.
Would it still be true that Rec's "initialization" operation needs to
be called right after the discriminant is read?  (Now it's possible to
make things work without it.)

I guess what disturbs me about this is that the rest of the language
appears to be very explicit about when "initialize" and "finalize"
operations are performed (including when an implementation has
permission to omit them).  But here's a case where, it seems,
initialize may be performed---or *must* be performed---and the
language doesn't say anything about it, even in a case where
initialization appears to be necessary.  The language says that
objects are initialized after being created, but it doesn't say
anything about 'Read creating an object, and now it appears to me that
this is a case where an anonymous object may not be necessary, which
means that no object would be created by 'Read, but an initialize
operation would need to be done anyway.  Maybe all this doesn't bother
you as much as it bothers me.  To me, something seems to be missing.

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

From: Randy Brukardt
Date: Friday, July 7, 2006  9:51 PM

This doesn't bother me because there has to be more than missing wording for
there to be a problem with the standard. There also has to be a sensible
interpretation of the Standard that both leads to an undesirable result and
doesn't violate any other rules. There are *lots* of things that aren't
spelled out in the Standard!

I don't see why you say "an initialize operation would need to be done
anyway". In the absence of some wording requiring Initialize to be called,
it shouldn't happen (as you note). Indeed, I think this case is very similar
to the initialization of the (optional) anonymous object for an aggregate.
That is, there is no explicit call to Initialize or Adjust on the empty
space before it is set to the aggregate values. That means that technically,
there is no initialization going on!

In your example:

>     type Rec (N : My_Int_Type := 0) is record
>         Component1 : Controlled_Type_1;
>         Component2 : Controlled_Type_2;
>         case N is
>             ...  -- assume some controlled types or arrays whose
>                  -- bounds depend on N are in here
>         end case;
>     end record;
>
> Suppose also that user-defined 'Read routines were present for
> My_Int_Type, Controlled_Type_1, and Controlled_Type_2, but not for
> Rec; and that Initialize routines were defined for Controlled_Type_1
> and _2 that set some global flags.  Now we do Rec'Read on some object.
> I maintain that, if the user-defined 'Read routines checked the global
> flags, the 'Read routine on My_Int_Type would always find that the
> initialization flags were clear, and the 'Read routines on
> Controlled_Type_1 and Controlled_Type_2 would always find that the
> flags were set, because *some* object of type Rec has to be
> initialized after N is read (in order to get the components in the
> variant part initialized correctly), and this initialization would
> have to call the user-defined Initialize routine for Controlled_Type_1
> and _2.  In fact, I'd say this is so definitely true that an ACATS
> test could be written that tests this.

I don't see this at all. If you had an aggregate for type Rec and you were
creating an anonymous object for it, you wouldn't call Initialize at all
unless the components were (explicitly) default initialized. Why would you
have to do something else here?? The rules say Initialize is called when
something is "initialized by default" -- which has a very specific technical
meaning. That doesn't happen here (it would have to say so). Moreover, the
value after the entire Read operation isn't going to be the default one.

I do agree that you have to Finalize old components before inserting the new
values, and Adjust and Finalize appropriately if there is an anonymous
object. If you don't do that, you'll get erroneous execution, which is not
possible here.

It is a little weird that the predefined 'Read needs magic (as a
user-defined one would need explicit objects, which of course would require
Initialize), but the alternative doesn't make sense. (Especially if the type
is limited! The object better be built-in-place, no matter how hard that
is.)

It would have been nice if 'Read was mentioned with aggregates in the notes
of the controlled type section. But streaming issues probably weren't
considered at all when the semantics of controlled types were defined. Not
that it matters, it seems to fall out properly.

It does appear to me that you need to override 'Read if you need something
other than pure value copying to happen during read-in (such as adjustment
of reference counts). That seems OK, it's necessary to do that in every
other case. (Again, this seems like more of a problem with controlled types
than with 'Read.)

As I said before, it would be good if there were AARM notes detailing the
interactions between Read and controlled objects, but I don't see any
language problems.

Anyway, if you still think there is a problem here (and there being a
problem relating to streams wouldn't surprise me!), please give an example
where the rules could be interpreted to get an incorrect answer but without
erroneous execution. It also would help if you would suggest what you think
the rules for 'Read *should* say, in as much detail as possible.

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

From: Tucker Taft
Date: Friday, July 7, 2006 10:48 PM

I think it might be better to make a requirement
in this case (unconstrained, discriminated actual)
that *no* part of the actual parameter be modified if any
of the "above checks" fail (the phrase "above checks" in
this paragraph is unfortunately a bit vague).

I agree with Randy that Initialize wouldn't need to
be called if the values are read directly into an "empty"
anonymous object, similar to an aggregate.  But I
would also permit an implementation to create
a default-initialized temp using the values of
the discriminants, and then overwrite the fields
one at a time.  Effectively this would permit 'Read
to be implemented by using 'Input, where a temporary
default-initialized object is essentially *required*
(by RM 13.3.2(27/2)).

This permission would imply that you couldn't call 'Read
until Initialize for any controlled parts
had been elaborated. But that seems pretty reasonable
to me, since a call on 'Read is visibly a procedure call.
Aggregates don't permit calls on Initialize/Adjust
because they don't look like subprogram calls, and
they are used to define deferred constants.

To summarize, I would recommend:
   1) Require the actual not be modified if any of the
      "above checks" fail, when the actual is unconstrained
      with discriminants.
   2) Permit the default implementation of 'Read for types
      with defaulted discriminants to create
      temporary objects, optionally default-initialized.

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

From: Randy Brukardt
Date: Saturday, July 8, 2006  6:11 PM

> I agree with Randy that Initialize wouldn't need to
> be called if the values are read directly into an "empty"
> anonymous object, similar to an aggregate.  But I
> would also permit an implementation to create
> a default-initialized temp using the values of
> the discriminants, and then overwrite the fields
> one at a time.  Effectively this would permit 'Read
> to be implemented by using 'Input, where a temporary
> default-initialized object is essentially *required*
> (by RM 13.3.2(27/2)).

*Now* I'm "bothered", as Adam puts it. This permission would mean that you
couldn't reason in any way about the behavior of a predefined 'Read. In
particular, with this permission, it might call Initialize, and it might
not. That is, this might be an unpaired creation (like an aggregate) and it
might be a paired creation (like an object declaration). If you're doing
reference counts, for instance, you could not allow the predefined read to
be used because of this permission. Indeed, I don't know if there would be
any real controlled types where you could use the predefined Read.

Note that I'm not talking about a case where an anonymous object is
introduced and properly finalized. I don't think any permission is needed
for that for non-limited types, that's always allowed.

Currently, there is a well-defined (if not well-documented) semantics for
predefined 'Read: it works like an aggregate (with or without an anonymous
object). That may not be the nicest possible semantics, but at least it is
defined and consistent. Allowing a semantics which is inconsistent with the
rest of controlled types isn't going to help.

[Truth is, I can't think of any meaningful semantics for 'Read for
controlled types. It can't pair properly, no matter what definition you give
it, and if it doesn't, you have no choice but to override it. The
implementer of a controlled type can simply avoid aggregates to avoid the
pairing problem with them, but that doesn't work with 'Read. It would be
best to make it unavailable for such types -- except that would be a
contract model violation.]

> This permission would imply that you couldn't call 'Read
> until Initialize for any controlled parts
> had been elaborated. But that seems pretty reasonable
> to me, since a call on 'Read is visibly a procedure call.

I don't think that such a call is possible; 'Read is a procedure call and as
such has to occur in a body. Either the body hasn't been elaborated yet
(error) or Initialize has been elaborated. That's good, too, because
requiring an elaboration check on the *predefined* version of 'Read could be
very painful to implement.

> Aggregates don't permit calls on Initialize/Adjust
> because they don't look like subprogram calls, and
> they are used to define deferred constants.
>
> To summarize, I would recommend:
>    1) Require the actual not be modified if any of the
>       "above checks" fail, when the actual is unconstrained
>       with discriminants.
>    2) Permit the default implementation of 'Read for types
>       with defaulted discriminants to create
>       temporary objects, optionally default-initialized.

If by this you mean that a temporary object can be introduced (with all of
the rules of that), OK, but I think that's already allowed so I don't know
why a permission would be necessary.

The semantics of the predefined 'Read of a type with a controlled part is:

    1) Read the discriminants if necessary, and perform the "above checks".
    2) Finalize the object passed.
    3) Read the rest of the data, and build it directly in the object.

or (for a type where 'Read has to read the discriminants):

    1) Read the discriminants.
    2) Create and initialize an anonymous object with the appropriate
discriminants.
    3) Read the rest of the data into the anonymous object.
    4) Finalize the object passed.
    5) Copy the anonymous object into the object passed, and Adjust the
data.
    6) Finalize the anonymous object.

Nope, the latter doesn't work: beside the extra Initialize/Finalize pair,
there is an extra Adjust that doesn't exist in the first scenario. That
breaks all of the invariants. The second case has to look like an anonymous
aggregate:

    1) Read the discriminants.
    2) Create an anonymous object with the appropriate discriminants, but do
not initialize!
    3) Read the rest of the data into the anonymous object.
    4) Finalize the object passed.
    5) Copy the anonymous object into the object passed, and Adjust the
data.
    6) Finalize the anonymous object.

Now it's consistent with the first case.

So, I guess my point is that Initialize must never, ever be called in the
predefined 'Read. Or we have to change the semantics dramatically so that it
is *always* called. Else you end up with many cases where the pairing of
controlled operations changes depending on the implementation, and that
makes no sense.

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

From: Tucker Taft
Date: Saturday, July 8, 2006  10:10 PM

> *Now* I'm "bothered", as Adam puts it. This permission would mean that you
> couldn't reason in any way about the behavior of a predefined 'Read. In
> particular, with this permission, it might call Initialize, and it might
> not. That is, this might be an unpaired creation (like an aggregate) and it
> might be a paired creation (like an object declaration). If you're doing
> reference counts, for instance, you could not allow the predefined read to
> be used because of this permission. Indeed, I don't know if there would be
> any real controlled types where you could use the predefined Read.

Sorry, I didn't mean to imply that the normal invariants may be
violated.  If you default initialize controlled components of the
anonymous object, then when you overwrite them you must
finalize them immediately prior to their being overwritten.

> Note that I'm not talking about a case where an anonymous object is
> introduced and properly finalized. I don't think any permission is needed
> for that for non-limited types, that's always allowed.

I am probably only talking about this kind of anonymous object.
But can you say where this permission is to be found in the RM?

> Currently, there is a well-defined (if not well-documented) semantics for
> predefined 'Read: it works like an aggregate (with or without an anonymous
> object). That may not be the nicest possible semantics, but at least it is
> defined and consistent. Allowing a semantics which is inconsistent with the
> rest of controlled types isn't going to help.
> 
> [Truth is, I can't think of any meaningful semantics for 'Read for
> controlled types. It can't pair properly, no matter what definition you give
> it, and if it doesn't, you have no choice but to override it. The
> implementer of a controlled type can simply avoid aggregates to aviod the
> pairing problem with them, but thet doesn't work with 'Read. It would be
> best to make it unavailable for such types -- except that would be a
> contract model violation.]

I don't completely understand your problem here.  Can you
give a simple example?

>> To summarize, I would recommend:
>>    1) Require the actual not be modified if any of the
>>       "above checks" fail, when the actual is unconstrained
>>       with discriminants.
>>    2) Permit the default implementation of 'Read for types
>>       with defaulted discriminants to create
>>       temporary objects, optionally default-initialized.
> 
> If by this you mean that a temporary object can be introduced (with all of
> the rules of that), OK, but I think that's already allowed so I don't know
> why a permission would be necessary.

If such a permission already exists, great.  I just don't
know where it is.

> The semantics of the predefined 'Read of a type with a controlled part is:
> 
>     1) Read the discriminants if necessary, and perform the "above checks".
>     2) Finalize the object passed.
>     3) Read the rest of the data, and build it directly in the object.
> 
> or (for a type where 'Read has to read the discriminants):
> 
>     1) Read the discriminants.
>     2) Create and initialize an anonymous object with the appropriate
> discriminants.
>     3) Read the rest of the data into the anonymous object.
>     4) Finalize the object passed.
>     5) Copy the anonymous object into the object passed, and Adjust the
> data.
>     6) Finalize the anonymous object.
> 
> Nope, the latter doesn't work: beside the extra Initialize/Finalize pair,
> there is an extra Adjust that doesn't exist in the first scenario. That
> breaks all of the invariants. The second case has to look like an anonymous
> aggregate:
> 
>     1) Read the discriminants.
>     2) Create an anonymous object with the appropriate discriminants, but do
> not initialize!
>     3) Read the rest of the data into the anonymous object.
>     4) Finalize the object passed.
>     5) Copy the anonymous object into the object passed, and Adjust the
> data.
>     6) Finalize the anonymous object.
> 
> Now it's consistent with the first case.

I would claim you can default initialize, so long as you finalize
each controlled component prior to overwriting it with the data from
the stream.

> So, I guess my point is that Initialize must never, ever be called in the
> predefined 'Read. Or we have to change the semantics dramatically so that it
> is *always* called. Else you end up with many cases where the pairing of
> controlled operations changes depending on the implementation, and that
> makes no sense.

I don't see the problem so long as each component that is Initialized
is Finalized prior to being overwritten from the data from the stream.
That is what would happen if you implemented it in "normal" Ada
source, in any case.

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

From: Adam Beneschan
Date: Monday, July 10, 2006  11:42 AM

> Currently, there is a well-defined (if not well-documented) semantics for
> predefined 'Read: it works like an aggregate (with or without an anonymous
> object). 

Actually, I'd say "not documented at all" rather than "not
well-documented".  I couldn't find anything in the RM that says, or
implies, that predefined 'Read works like an aggregate.  And if it's
well-defined but not well-defined in the RM, where is the definition?
Is it somewhere in a locked safe in the ARG offices?  Do you need a
special key to get in?  Do you need to know a secret password?  OK,
I'm just being silly here, and I'd better stop now lest I start
sounding like a certain c.l.a poster who thinks that ARG is a big
conspiracy to hijack the language and turn themselves into a
priesthood who prevents ordinary lay users from knowing what the
language really says and rob Americans of their precious body
fluids...........

But maybe that's one of the things that bothered me.  If there are
well-defined semantics for predefined 'Read but they were missing from
the RM (or an important aspect of them was missing), perhaps that's
what caused the vague feeling on my part that something was amiss.


> Nope, the latter doesn't work: beside the extra Initialize/Finalize pair,
> there is an extra Adjust that doesn't exist in the first scenario. That
> breaks all of the invariants. The second case has to look like an anonymous
> aggregate:
> 
>     1) Read the discriminants.
>     2) Create an anonymous object with the appropriate discriminants, but do
> not initialize!
>     3) Read the rest of the data into the anonymous object.
>     4) Finalize the object passed.
>     5) Copy the anonymous object into the object passed, and Adjust the
> data.
>     6) Finalize the anonymous object.
> 
> Now it's consistent with the first case.
> 
> So, I guess my point is that Initialize must never, ever be called in the
> predefined 'Read. Or we have to change the semantics dramatically so that it
> is *always* called. Else you end up with many cases where the pairing of
> controlled operations changes depending on the implementation, and that
> makes no sense.

I'm not sure exactly which Initialize you mean must never be
called---on the entire record, or on individual components?

Initialize *must* be called on each individual component before 'Read
is called on the component.  Perhaps this isn't necessary if the
predefined 'Read for the component is called; but if the component
type has a user-defined 'Read, the parameter must not be uninitialized
garbage.  [That's what led to the bug in the original test case.]

Assuming the call looks like "Rec'Read (Str, R);": I probably created
part of the confusion by assuming that an "initialize" operation must
be called on the type Rec.  Maybe that's not strictly true.  It seems
certainly true that, if Rec is a discriminant record with defaults,
any components that depend on the discriminant have to be Initialized
before being passed to 'Read (particularly to a user-defined 'Read).
If a component X does not depend on a discriminant, then R.X could be
passed to 'Read without an Initialize call, and things would still
work; but if Anon.X is passed to 'Read where Anon is an anonymous
object, then Anon.X still has to be initialized at some point.  [And
if R is actually constrained, then none of the Initialize routines
really need to be called, since no array bounds will change and no
components will come into existence that didn't already exist in R.]

Given all this, it seemed to me that since a compiler may have already
generated a subroutine for initializing objects of type Rec, it would
make sense for the compiler to generate a call to this subroutine
before calling 'Read on the components.  This isn't the only possible
implementation---it could call Initialize on each individual component
before passing it to 'Read---but it seems like one possibility.  Now,
though, it's beginning to look like this implementation would be
incorrect---or that it would be correct according to the current RM
but wrong according to what the semantics *should* be.

Anyway, unless I've grossly misunderstood this conversation (a good
possibility), it does look like some guidance is needed as far as what
Initialize operations are required, which ones are allowed but not
required, and which ones are disallowed.

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


Questions? Ask the ACAA Technical Agent