Version 1.1 of acs/ac-00158.txt

Unformatted version of acs/ac-00158.txt version 1.1
Other versions for file acs/ac-00158.txt

!standard 13.13.2          08-03-05 AC95-00158/01
!class Amendment 08-03-05
!status received no action 08-03-05
!status received 08-02-06
!subject
!summary
!appendix

!topic Availability of stream attributes
!reference RM 13.13.2
!from Adam Beneschan 08-02-06
!discussion


I'm having some difficulty understanding the rules about availability
of stream attributes.

As I understand it:

   package Pak1 is
      type T1 is limited record
         F1 : Integer;
      end record;
   private
      procedure Read_Proc (...);
      for T1'Read use Read_Proc;
   end Pak1;

It is illegal to call T1'Read except in places where the private part
of Pak1 is visible (i.e. the body of Pak1, or the private part or body
of a child of Pak1).  Right?

But if T1 is not limited:

   package Pak1 is
      type T1 is record
         F1 : Integer;
      end record;
   private
      procedure Read_Proc (...);
      for T1'Read use Read_Proc;
   end Pak1;

T1'Read can be called from anywhere, and always results in a call to
Read_Proc even in places where the private part of Pak1 isn't
visible.  Am I right so far?

What happens here?

   package Pak2 is
      type T2 is limited record
         F2 : Integer;
      end record;
      procedure Read_T2 (...);
      for T2'Read use Read_T2;
   end Pak2;

   with Pak2;
   package Pak3 is
      type T3 is new Pak2.T2;
   private
      procedure Read_T3 (...);
      for T3'Read use Read_T3;
   end Pak3;

   with Pak3;
   procedure Proc4 is
      Obj : Pak3.T3;
   begin
      ...
      Pak3.T3'Read (Some_Stream'access, Obj);
   end;

If I understand the rules correctly (good luck with that), the 'Read
attribute is inherited for T3 in the visible part of Pak3, and then
overridden in the private part; but when T3'Read is called in Proc4,
since the private part of Pak3 is not visible, the result is that the
inherited version of the attribute is called, which means that Read_T2
will be called.  As I understand the discussion in AI-195, we don't
want Read_T3 to be called for a limited type, in places where the
private part of Pak3 isn't visible, because doing so would break
privacy.

But does any of this change if the word "limited" is removed from T2's
declaration?  Would T3'Read call Read_T2, or Read_T3?

The reason this is a bit confusing is that in the case where a type is
not limited and not derived, if I've understood the rules correctly in
the first part of this post, an attribute specification in the private
part still has an effect even when the private part is not visible.
But if a type is *derived* and not limited, then I'm not clear on
whether the attribute specification in the private part has a similar
effect or not, if there is also an inherited attribute.

I realize this is all pretty obscure and may not have an effect on any
real-life programs, but as an implementor I do want to make sure I
understand the impact of the rules correctly.

Thanks for any help you can provide.

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

From: Gary Dismukes
Date: Wednesday, February 6, 2008  6:03 PM

> I'm having some difficulty understanding the rules about availability
> of stream attributes.
>
> As I understand it:
>
>    package Pak1 is
>       type T1 is limited record
>          F1 : Integer;
>       end record;
>    private
>       procedure Read_Proc (...);
>       for T1'Read use Read_Proc;
>    end Pak1;
>
> It is illegal to call T1'Read except in places where the private part
> of Pak1 is visible (i.e. the body of Pak1, or the private part or body
> of a child of Pak1).  Right?

Right.

> But if T1 is not limited:
>
>    package Pak1 is
>       type T1 is record
>          F1 : Integer;
>       end record;
>    private
>       procedure Read_Proc (...);
>       for T1'Read use Read_Proc;
>    end Pak1;
>
> T1'Read can be called from anywhere, and always results in a call to
> Read_Proc even in places where the private part of Pak1 isn't
> visible.  Am I right so far?

Also right.

>
> What happens here?
>
>    package Pak2 is
>       type T2 is limited record
>          F2 : Integer;
>       end record;
>       procedure Read_T2 (...);
>       for T2'Read use Read_T2;
>    end Pak2;
>
>    with Pak2;
>    package Pak3 is
>       type T3 is new Pak2.T2;
>    private
>       procedure Read_T3 (...);
>       for T3'Read use Read_T3;
>    end Pak3;
>
>    with Pak3;
>    procedure Proc4 is
>       Obj : Pak3.T3;
>    begin
>       ...
>       Pak3.T3'Read (Some_Stream'access, Obj);
>    end;
>
> If I understand the rules correctly (good luck with that), the 'Read
> attribute is inherited for T3 in the visible part of Pak3, and then
> overridden in the private part; but when T3'Read is called in Proc4,
> since the private part of Pak3 is not visible, the result is that the
> inherited version of the attribute is called, which means that Read_T2
> will be called.  As I understand the discussion in AI-195, we don't
> want Read_T3 to be called for a limited type, in places where the
> private part of Pak3 isn't visible, because doing so would break
> privacy.

The "overriding" Read_T3 should be called in that case AFAIK.  I don't
see where in AI-195 that specific case is discussed (but I might have
missed it, it's a long AI).  The behavior in such cases shouldn't depend
on whether the type is limited or not.  If there's an explicitly specified
stream attribute, that's the one that should be used, assuming the
attribute is available.

> But does any of this change if the word "limited" is removed from T2's
> declaration?  Would T3'Read call Read_T2, or Read_T3?

No, that shouldn't affect this case, the subprogram for the specified
attribute one should be called in either case.  I'm not sure that's
clearly derivable from the rules however (what a surprise with
stream attributes...), so clarification may be in order.  I don't
even see where the RM defines that a specified stream attribute gets
called instead of the default or inherited version, though I may just
be missing it.

> The reason this is a bit confusing is that in the case where a type is
> not limited and not derived, if I've understood the rules correctly in
> the first part of this post, an attribute specification in the private
> part still has an effect even when the private part is not visible.
> But if a type is *derived* and not limited, then I'm not clear on
> whether the attribute specification in the private part has a similar
> effect or not, if there is also an inherited attribute.

Regardless of what the rules say (or don't say), I don't think that's
the desired behavior.  That is, I believe that an inherited stream
attribute should always be superseded by a specified one, whether
or not the latter is in the visible or private part.  I don't see
that as privacy breaking, because the specified attribute subprogram
is defining the implementation of the attribute, and it would be
very confusing if the attribute behaved differently depending on
where the attribute is referenced.

> I realize this is all pretty obscure and may not have an effect on any
> real-life programs, but as an implementor I do want to make sure I
> understand the impact of the rules correctly.

I agree it's important to understand these rules, and I don't even find
this all that obscure to be asking about (but then I'm an implementor:-).

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

From: Robert A. Duff
Date: Wednesday, February 6, 2008  6:26 PM

>...  As I understand the discussion in AI-195, we don't
> want Read_T3 to be called for a limited type, in places where the
> private part of Pak3 isn't visible, because doing so would break
> privacy.

Gary answered your questions, but I'll add one comment:

"Privacy breaking" is a purely compile-time concept.
We try to avoid cases where the compiler would have to peek
into the private part in order to determine whether some client
is legal.

But run time is an entirely different story.  For example, the compiler has to
look at the private part to know whether it is allowed to pass parameters by
reference or by copy.

The question of which thing should be called is a run-time issue,
and therefore cannot break privacy.

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

From: Adam Beneschan
Date: Wednesday, February 6, 2008  7:01 PM

...
> The "overriding" Read_T3 should be called in that case AFAIK.  I don't
> see where in AI-195 that specific case is discussed (but I might have
> missed it, it's a long AI).  The behavior in such cases shouldn't depend
> on whether the type is limited or not.  If there's an explicitly specified
> stream attribute, that's the one that should be used, assuming the
> attribute is available.
>
> Regardless of what the rules say (or don't say), I don't think that's
> the desired behavior.  That is, I believe that an inherited stream
> attribute should always be superseded by a specified one, whether
> or not the latter is in the visible or private part.  I don't see
> that as privacy breaking, because the specified attribute subprogram
> is defining the implementation of the attribute, and it would be
> very confusing if the attribute behaved differently depending on
> where the attribute is referenced.

OK, thanks for straightening me out.  I may have been confusing this
with subprograms are inherited.

   package Pak5 is
      type T5 is ...;
      procedure Proc (X : T5);
   end Pak5;

   package Pak6 is
      type T6 is new Pak5.T5;
   private
      procedure Proc (X : T6);
   end Pak6;

When you call Proc on an object of type T6, you may get either the
inherited one or the overriding one depending on what's visible at the
point of the call.  But I guess inherited stream attributes don't work
the same way.  That's fine---I just wasn't sure.

Thanks, Gary and Bob, for your help.

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

From: Tucker Taft
Date: Wednesday, February 6, 2008  7:49 PM

Stream attributes are more like dispatching operations,
in that visibility determines whether the operation is
available at all, but you *always* invoke the overriding
even if it is not visible.  If the operation has formal
parameter names and defaults, those always follow
visibility rules, but you can't use named notation or
defaults when calling an attribute subprogram anyway.

The relevant piece of the RM that indicates that you always
get the overriding is 13.3(18.1):

   If an operational aspect is specified for an entity
   (meaning that it is either directly specified or
   inherited), then that aspect of the entity is as specified.

Sounds kind of redundant, but the key thing in this context
is that it doesn't matter whether the operational item
happens in the private part.  The aspect is as specified.
On the other hand, for limited types, whether the operation
is "available" at all is based on visibility.

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


Questions? Ask the ACAA Technical Agent