Version 1.1.1.1 of ais/ai-00201.txt

Unformatted version of ais/ai-00201.txt version 1.1.1.1
Other versions for file ais/ai-00201.txt

!standard 04.06 (16)          98-04-01 AI95-00201/01
!class confirmation 98-03-27
!status No Action 10-0-2 98-04-01
!status received 98-03-27
!priority Medium
!difficulty Medium
!subject object subtype must statically match designated subtype
!summary 98-03-27
!question 98-03-27
!response 98-03-27
!appendix

!section 4.6(16)
!subject object subtype must statically match designated subtype
!reference RM95-4.6 (16)
!from Ted Baker
!reference 1998-15802.a Ted Baker  1998-2-25>>
!discussion

The following came up in the POSIX.5c ballot resolution.
POSIX.5c makes use of interfaces similar
to the following, for passing I/O buffers.
The fact that this is (apparently) illegal was not detected,
since earlier Ada compilers were not enforcing this rule.

procedure foo is
  type string_ptr is access all string;
  procedure p (s : string_ptr);
  procedure p (s : string_ptr) is
  begin null;
  end p;
  buf  : aliased string (1..10);
begin
  p (buf'access);
end foo;

We are now faces with the extremely embarassing need to
backrack to the C-language equivalent:

with system;
procedure fooc is
  procedure p (s : system.address; len : natural);
  procedure p (s : system.address; len : natural) is
  begin null;
  end p;
  buf  : aliased string (1..10);
begin
  p (buf'address, buf'length);
end fooc;

This very bad PR for the Ada95 language.
Ada95 seems to provide a better way than C
to express this kind of interface, with the
additional safety features of type checking for components
and no chance of accidentally passing the wrong size.

What makes this even more absurd is that there is
no implementation reason for this restriction.
After all, if the user had declared

buf : aliased string := "garbage initial value";

Then "p (buf'access);" would be legal, and it is
equivalent work for the implementation.

I strongly believe that this problem is serious enough to make a
corregendum to the ARM.

ARM references, courtesy of POSIX.5c balloter Niklas Holsti:

  LRM ref.   Implies that:
  --------   -------------
  3.2(3)     Access types are elementary.
  6.2(3)     An elementary type is passed by copy.
  6.4.1(11)  An "in" parameter passed by copy is converted to the
             nominal subtype of the formal parameter.
  6.1(24)    An access parameter is of a general access-to-variable
             type.
  4.6(16)    In a conversion to a a general access type where the
             target designated type is not tagged, either the designated
             subtypes shall statically match or the target designated
             subtype shall be discriminated and unconstrained.
             ("Match" seems to mean "be identical", since the LRM
             index has no entry on "match of subtypes").
  3.7(8)     An array type is not a discriminated type, therefore
             static subtype match is required in 4.6(16).

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

!section 4.6(16)
!subject object subtype must statically match designated subtype
!reference RM95-4.6 (16)
!from Norman Cohen
!reference 1998-15802.a Ted Baker  1998-2-25
!reference 1998-15803.a Norman H Cohen  1998-2-26>>
!discussion

I think the rule should stay as is, so that a compiler has the choice of
letting access-to-unconstrained contain or point to dope, even while
access-to-constrained does not.

(The trick of putting the dope just BEFORE the address pointed to is not
generally available in Ada 95 because a packed record, or one with a record-rep
clause, could have aliased String(1 .. 10) components.)

It's not all that terrible to have to write

   Buf: aliased String := (1 .. 10 => ' ');

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

!section 4.6(16)
!subject object subtype must statically match designated subtype
!reference RM95-4.6 (16)
!reference 1998-15802.a Ted Baker  1998-2-25
!from Randy Brukardt
!reference 1998-15804.a Randy Brukardt  1998-2-26>>
!discussion

>What makes this even more absurd is that there is
>no implementation reason for this restriction.

This is completely wrong.  There is a MAJOR implementation problem here.
 It is caused by the need for unconstrained arrays to have array
descriptors.

>After all, if the user had declared

>buf : aliased string := "garbage initial value";

>Then "p (buf'access);" would be legal, and it is equivalent work for the
implementation.

Not really.  When you declare "aliased string", the compiler will create an
array as part of, or alongside the object.  Taking 'access of the object
then can include the necessary array descriptor.

If you have instead

buf : aliased string(1..10);

most compilers will not generate any array descriptor.  Then, when you take
'access, you would need to create a descriptor - but how can you get the
lifetime right?  You can't allocate the descriptor locally, because the
access type probably will last longer than that.  If you allocate it from
the heap, you will never know when it is safe to deallocation it, so you
will have a storage leak.

We discovered this during the U/I work.  I was prepared to make "aliased"
change the representation of items, but I believe that the language design
team decided that they didn't want "aliased" to change the representation
of items, and therefore added the rule you are complaining about.

>I strongly believe that this problem is serious enough to make a
>corregendum to the ARM.

The impact on implementations would be substantial, more memory would be
consumed by programs, aliased arrays which were stored in disk files would
not be readable with "corrected" compilers, and some previously legal
representation clauses would have to be rejected.

This is much too major of a change for the ARG to make.  I recommend that
the rule stand.

>The fact that this is (apparently) illegal was not detected,
>since earlier Ada compilers were not enforcing this rule.

Janus/Ada has always enforced the rule (since it was put in after we
discovered the implementation problem).  The problem is that the ACVC had a
couple of tests which insisted that the rule NOT be implemented.  We of
course disputed the tests, and they were eventually withdraw, but the net
effect was that ACVC 2.0.1 encouraged the wrong implementation, and did
nothing to check for the correct implementation.

>We are now faces with the extremely embarassing need to
>backtrack to the C-language equivalent:

>with system;
>procedure fooc is
>  procedure p (s : system.address; len : natural);
>  procedure p (s : system.address; len : natural) is
>  begin null;
>  end p;
>  buf  : aliased string (1..10);
>begin
>  p (buf'address, buf'length);
>end fooc;

Yes, we've run into this in Claw.  But you don't have to all the way to
System.Address.  You still can get most of the type checking by making the
declaration:

procedure foo_better is
  type Access_Character is access all Character;
  type better_string is array (positive range <>) of aliased Character;
  procedure p (s : Access_Character; len : natural);
  procedure p (s : Access_Character; len : natural) is
  begin null;
  end p;
  buf  : better_string (1..10);
begin
  p (buf(1)'access, buf'length);
end foo_better;

I also find the whole notion of needing to pass a pointer at a string
dubious.  While C bindings such as Win32 is full of them, we have not found
a single case yet in the construction of Claw where we had to make that
visible to the user.

In every case we've seen, you can use either "Item : in String" (if the
item is only going to read),
or "Item : in out String" if the item is going to written.  I wonder if
your POSIX people need to work harder to provide an appropriate Ada
binding.  I certainly don't want to change the language so a dubious coding
practice can be supported.

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

!section 4.6(16)
!subject object subtype must statically match designated subtype
!reference RM95-4.6 (16)
!from Robert Dewar
!reference 1998-15802.a Ted Baker  1998-2-25
!reference 1998-15803.a Norman H Cohen  1998-2-26
!reference 1998-15809.a Robert Dewar 1998-2-27>>
!discussion

Norman says

<<I think the rule should stay as is, so that a compiler has the choice of
  letting access-to-unconstrained contain or point to dope, even while
  access-to-constrained does not.

  (The trick of putting the dope just BEFORE the address pointed to is not
  generally available in Ada 95 because a packed record, or one with a
  record-rep clause, could have aliased String(1 .. 10) components.)>>

Addressing the second paragraph, this is a red herring. It is perfectly
fine to put the dope just before the address to work is perfectly fine
in Ada 95, and this would be so even if dope is required for constrained
components. This is because a pragma Pack in the situation Norman suggests
would not be required to eliminate this dope, and in the case of a record
rep clause, there is nothing that suggests that the record rep clause that
tried to eliminate this dope would have to be accepted. There is nothing
in the RM that suggests or requires the way that an aliased array must
be represented.

Randy says

<<This is completely wrong.  There is a MAJOR implementation problem here.
 It is caused by the need for unconstrained arrays to have array
 descriptors.>>

The use of caps for MAJOR here does not compensate for the fact that this
is a very weak argument. Indeed it was this argument that caused the very
unwise decision in the design of Ada 95 that is under discussion. FOr the
sake of saving a small amount of space in a relatively unusual case (aliased
components and variables are not that common in the first place), we have

  (a) Annoyingly damaged the functionality of the language. Norman's claim
      that it is a minor problem to have to do junk initializations seems
      quite bogus to me. Such initializations waste time and space, and
      are quite unnatural.

  (b) Created a nasty "experts-only" glitch in the language. We constantly
      see users get caught on this. If you compare the two declarations

            a : aliased string := "hello";
            a : aliased string (1 .. 5) := "hello";

      It is a big surprise to users that these are not equivalent, and the
      whole business of nominal subtypes is a nasty corner of the language.

What we have done here is to repeat the mistake made with default
discriminants, where initialization is used for two different purposes.

Now we have the situation in Ada 95, that initialiazation is used for two
completely different purposes. One to provide an initial value, and the
other to make it possible to get a proper aliased variable with the
appropriate nominal subtype.

<<We discovered this during the U/I work.  I was prepared to make "aliased"
change the representation of items, but I believe that the language design
team decided that they didn't want "aliased" to change the representation
of items, and therefore added the rule you are complaining about.>>

Of course aliased is expected to change the representation of items in the
general case. The LDT made no such decision, and it is quite clear from the
RM that this kind of change of representation is envisioned.

In particular, there is nothing at all to stop an implementation putting in
the dope vector in all cases anyway in the aliased case and not in the
non-aliased case, and in fact I believe this is exactly what GNAT does, or
if it does not, we have certainly discussed this possibility.

<<The impact on implementations would be substantial, more memory would be
  consumed by programs, aliased arrays which were stored in disk files would
  not be readable with "corrected" compilers, and some previously legal
  representation clauses would have to be rejected.>>

I regard the first clause here as bogus, the minuscule extra amount of
memory (for some implementations -- for GNAT it would cause absolutely no
additional space when fat pointers were used) is barely noticable, let alone
substantial.

THe points about aliased arrays stored in disk files etc are valid, and in
fact I do not think we could make the change at this stage.

<<I also find the whole notion of needing to pass a pointer at a string
  dubious.  While C bindings such as Win32 is full of them, we have not found
  a single case yet in the construction of Claw where we had to make that
  visible to the user.

  In every case we've seen, you can use either "Item : in String" (if the
  item is only going to read),
  or "Item : in out String" if the item is going to written.  I wonder if
  your POSIX people need to work harder to provide an appropriate Ada
  binding.  I certainly don't want to change the language so a dubious
  coding practice can be supported.>>

This seems an entirely reasonable suggestion. I do not understand the
reluctance to move to this. Such an array will be passed by reference
by any compiler that follows the implementation advice in B.3(70).
It seems perfectly reasonable for an implementation of a binding
of this kind to assume that this implementation advice is followed.

Indeed, either you take the position that your binding is a conceptual
thing, and the implementor can implement it however they like, or you
have in mind a thin binding, but in that case, you *HAVE* to assume
the compiler is following the implementation advice, or else there
is nothing to say.

In other words, the use of an in or in-out parameter is no more
implementation dependent than the use of an access parameter. Proper
handling of the former depends on para 70, and proper handling of
the latter depends on para  68.

Ted says that this damages the reputation of Ada, but I think all that
is wrong here is an injudicious decision in the design of the binding
that is easily corrected. The use of Address seems very unfortunate.

Ted, can you explain why you cannot simply use a reference parameter
(i.e. in or in out array) here. This would seem to solve all your
problems.

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

!section 4.6(16)
!subject object subtype must statically match designated subtype
!reference RM95-4.6 (16)
!from Norman Cohen
!reference 1998-15802.a Ted Baker  1998-2-25
!reference 1998-15803.a Norman H Cohen  1998-2-26
!reference 1998-15810.a Ted Baker  1998-2-27>>
!discussion

Based on Randy's comments, and other negative responses, I'm
persuaded that this issue is not worth pushing.  However, I
thought I should respond to the following:

| It's not all that terrible to have to write
|    Buf: aliased String := (1 .. 10 => ' ');

I guess I don't mind having to write the above, but this issue
came up because Drafts 1..3 of IEEE Std 1003.5c (Ada binding for
Sockets and XTI interfaces) passed buffers as access parameters,
and the balloters objected to having to do the above.  As a
consequence, the next ballot draft will use type System.Address
for all parameters that are references to buffers.

I wrote the original AI because I felt embarassed that Ada95
had tantalized us with a "type safe" interface here, and we were
ending up going back to the equivalent of C "void *".  Since then,
I have heard another argument in support of the untyped interface,
so I don't feel so strongly about it.  The other argument is
that when doing communications people typically are converting
between typed internal objects and uptyped octet-streams anyway,
so it is more efficienct and more "honest" to let them just take
'Address of any old object and present it as an octet buffer.

Therefore, please consider 19901-802a withdrawn.

--Ted Baker

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

!section 4.6(16)
!subject object subtype must statically match designated subtype
!reference RM95-4.6 (16)
!reference 1998-15802.a Ted Baker  1998-2-25
!reference 1998-15803.a Norman H Cohen  1998-2-26
!from Bob Duff
!reference 1998-15811.a Robert A Duff  1998-2-27>>
!discussion

Norman says:

> I think the rule should stay as is, so that a compiler has the choice of
> letting access-to-unconstrained contain or point to dope, even while
> access-to-constrained does not.

Well, I'm inclined to be conservative, and keep the rule as is.

But I must say, access-to-constrained-array has got to be a rarely used
feature.  The vast majority of access types point to records, and of the
remainder, I'd bet that most designated array types are UNconstrained.
If you know the size of a data structure, you can usually use the thing
itself, rather than a pointer to it.  My point is that the efficiency
issue, of whether or not to store an extra 8 or 16 bytes of dope, is
irrelevant.

> (The trick of putting the dope just BEFORE the address pointed to is
> not generally available in Ada 95 because a packed record, or one with
> a record-rep clause, could have aliased String(1 .. 10) components.)

I think the "trick" *does* work, and in fact IMHO it's the preferable
method.  If a composite type is packed, and some component is aliased,
the compiler has to essentially turn off packing for that component --
or partially turn it off.  After all, pragma Pack normally means to put
a Boolean component into a single bit, but if the Boolean component is
aliased, it has to be addressable, which probably means at least 8 bits.
Likewise, if a record_rep_clause tries to put an aliased component in a
place where it won't fit, the program is simply illegal (for that
implementation).

Removing the rule in question wouldn't change this fact -- it would
simply mean that all aliased arrays get dope before them (assuming the
compiler doesn't choose to attach the dope to the access values).

> It's not all that terrible to have to write
>
>    Buf: aliased String := (1 .. 10 => ' ');

Well, it's a wart.  Perhaps not "terrible".

- Bob

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

!section 4.6(16)
!subject object subtype must statically match designated subtype
!reference RM95-4.6 (16)
!reference 1998-15802.a Ted Baker  1998-2-25
!reference 1998-15804.a Randy Brukardt  1998-2-26
!from Bob Duff
!reference 1998-15812.a Robert A Duff  1998-2-27>>
!discussion

> If you have instead
>
> buf : aliased string(1..10);
>
> most compilers will not generate any array descriptor.

If the rule were relaxed, then compilers would have to generate an array
descriptor "next to" buf (assuming they use the model where an
access-to-array is a single address pointing to contiguous
dope-plus-data).

This hardly seems like a major difficulty in theory.  As I recall, it
was more of a "don't force compiler changes" sort of decision.  On the
other hand, I'm not sure I completely understand that, now.  Consider:

    X: constant String := "Hello, world.";

An Ada 83 compiler did not *need* to store any dope, anywhere, for X --
it could simply know (at compile time) that the bounds are 1..13.  (If
we then pass X to an unconstrained formal, we need to manufacture dope
at the call site, though.)  I don't know how many Ada 83 compilers did
it that way, but certainly:

    X: aliased String := "Hello, world.";

needs dope in Ada 95.  So every Ada 95 compiler must be prepared to put
dope next to stack-allocated arrays of unconstrained nominal subtype.
(Or else choose the other representation of access types, where the dope
lives with the access values.)

>...Then, when you take
> 'access, you would need to create a descriptor - but how can you get the
> lifetime right?  You can't allocate the descriptor locally, because the
> access type probably will last longer than that.  If you allocate it from
> the heap, you will never know when it is safe to deallocation it, so you
> will have a storage leak.

Clearly, the dope has the same lifetime as the data.  Therefore, the
obvious implementation is to allocate it with the data, at the same
time, in the same place.  I agree that trying to manufacture it on the
heap is not a reasonable implementation.

> We discovered this during the U/I work.  I was prepared to make "aliased"
> change the representation of items, but I believe that the language design
> team decided that they didn't want "aliased" to change the representation
> of items, and therefore added the rule you are complaining about.

"Aliased" can *certainly* change the representations of things.  They
need to be addressable.  They might need to be bigger and/or more
aligned than otherwise.  And they might need dope (as for X above).
They can't go in a register.

> >I strongly believe that this problem is serious enough to make a
> >corregendum to the ARM.
>
> The impact on implementations would be substantial, more memory would be
> consumed by programs, aliased arrays which were stored in disk files would
> not be readable with "corrected" compilers, and some previously legal
> representation clauses would have to be rejected.
>
> This is much too major of a change for the ARG to make.  I recommend that
> the rule stand.

I tend to agree.  In Ted's original example, it seems cleaner to pass
arrays, rather than access-to-arrays.

On the other hand, there are *some* C interfaces that pass
pointers-to-strings, where a non-null value means "use this buffer", and
a null value means "allocate a buffer that's big enough, and use that".
I find such an interface ugly, but sometimes you have to interface to
such a thing.

> >The fact that this is (apparently) illegal was not detected,
> >since earlier Ada compilers were not enforcing this rule.
>
> Janus/Ada has always enforced the rule (since it was put in after we
> discovered the implementation problem).  The problem is that the ACVC had a
> couple of tests which insisted that the rule NOT be implemented.  We of
> course disputed the tests, and they were eventually withdraw, but the net
> effect was that ACVC 2.0.1 encouraged the wrong implementation, and did
> nothing to check for the correct implementation.

Yet another example of the evils of training one's compiler to pass the
ACVC.  :-(

- Bob

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

!section 4.6(16)
!subject object subtype must statically match designated subtype
!reference RM95-4.6 (16)
!reference 1998-15802.a Ted Baker  1998-2-25
!reference 1998-15804.a Randy Brukardt  1998-2-26
!reference 1998-15812.a Bob Duff 1998-2-27
!from Randy Brukardt
!reference 1998-15813.a Randy Brukardt  1998-2-27>>
!discussion

>X: constant String := "Hello, world.";
>
>An Ada 83 compiler did not *need* to store any dope, anywhere, for X --
>it could simply know (at compile time) that the bounds are 1..13.  (If
>we then pass X to an unconstrained formal, we need to manufacture dope
>at the call site, though.)  I don't know how many Ada 83 compilers did
>it that way, but certainly:
>
>    X: aliased String := "Hello, world.";
>
>needs dope in Ada 95.  So every Ada 95 compiler must be prepared to put
>dope next to stack-allocated arrays of unconstrained nominal subtype.

Our compiler always has generated dope in each of these cases.

>"Aliased" can *certainly* change the representations of things.  They
>need to be addressable.  They might need to be bigger and/or more
>aligned than otherwise.  And they might need dope (as for X above).
>They can't go in a register.

Well, I don't think of "alignment" (which subsumes addressibility) as a
"representation" issue.  (I know, it is defined as one, but it doesn't have
the characteristics of a representation issue.)  I don't think they need to
be bigger (other than to match up with the alignment).

>On the other hand, there are *some* C interfaces that pass
>pointers-to-strings, where a non-null value means "use this buffer", and
>a null value means "allocate a buffer that's big enough, and use that".
>I find such an interface ugly, but sometimes you have to interface to
>such a thing.

I've found that the best way to handle such interfaces is to split it.
 After all we have overloading; C doesn't, so the designer probably came up
with that interface to avoid having multiple routines that do that same
thing.

The "use this buffer" routine gets implemented as an "in out String", and
the "allocate a buffer" routine either gets implemented as a function
returning a String, or returning a pointer to a string, or a procedure with
an out parameter which is a pointer to a string.  I prefer the function,
but it isn't always possible.

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

!section 4.6(16)
!subject object subtype must statically match designated subtype
!reference RM95-4.6 (16)
!from Robert Dewar
!reference 1998-15802.a Ted Baker  1998-2-25
!reference 1998-15803.a Norman H Cohen  1998-2-26
!reference 1998-15810.a Ted Baker  1998-2-27
!reference 1998-15815.a Robert Dewar 1998-2-28>>
!discussion

Ted, when you cut and paste a message, be sure to change the from line, you
cut and paste Norman Cohen's message and the from on 1998-15810.a shows
Norman Cohen :-)

You (Ted) said

<<I guess I don't mind having to write the above, but this issue
  came up because Drafts 1..3 of IEEE Std 1003.5c (Ada binding for
  Sockets and XTI interfaces) passed buffers as access parameters,
  and the balloters objected to having to do the above.  As a
  consequence, the next ballot draft will use type System.Address
  for all parameters that are references to buffers.>>

THe original design was incorrect.
The proposed redesign is a mistake.

Neiher mistake can be blamed on Ada!

THe proper solution here is to use an IN or IN OUT parameter, as has been
pointed out by others. I cannot imagine why you are making the mistake of
moving to an Address.

By the way, I find String a mightly peculiar type for this array. It would
seem much more appropriate to use System.Storage_Elements.Storage_Array.

Bob Duff in another message says

<<On the other hand, there are *some* C interfaces that pass
pointers-to-strings, where a non-null value means "use this buffer", and
a null value means "allocate a buffer that's big enough, and use that".
I find such an interface ugly, but sometimes you have to interface to
such a thing.
>>

Note that the Null_Parameter feature of DEC Ada (now reproduced in GNAT)
allows precisely this capability (specification of a null pointer value for
a by-reference parameter).

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

!section 4.6(16)
!subject object subtype must statically match designated subtype
!reference RM95-4.6 (16)
!from Ted Baker
!reference 1998-15802.a Ted Baker  1998-2-25
!reference 1998-15803.a Norman H Cohen  1998-2-26
!reference 1998-15810.a Ted Baker  1998-2-27
!reference as: 1998-15815.a Robert Dewar 1998-2-28>>
!reference 1998-15816.a Ted Baker  1998-3-1>>
!discussion

| <<I guess I don't mind having to write the above, but this issue
|   came up because Drafts 1..3 of IEEE Std 1003.5c (Ada binding for
|   Sockets and XTI interfaces) passed buffers as access parameters,
|   and the balloters objected to having to do the above.  As a
|   consequence, the next ballot draft will use type System.Address
|   for all parameters that are references to buffers.>>
| THe proper solution here is to use an IN or IN OUT parameter, as has been
| pointed out by others. I cannot imagine why you are making the mistake of
| moving to an Address.
| By the way, I find String a mightly peculiar type for this array. It would
| seem much more appropriate to use System.Storage_Elements.Storage_Array.

My original example used String, just for simplicity, not because
we really use String in the interfaces.  We ran into this problem
with several types in the POSIX.5c interface, some of which are
arrays of octets, some of which are arrays of iovecs, etc.

We decided to use System.Address for octet arrays, when they
are used as I/O buffers.  At the end the convincing reason was that
in practice people will be using these (socket and XTI I/O)
operations to transmit and receive objects of various user-defined
types, treating them as octet sequences.  For example:

   procedure Receive
      (Socket           : in  POSIX.IO.File_Descriptor;
       Buffer           : in  System.Address;
       Octets_Requested : in  POSIX.IO_Count;
       Octets_Received  : out POSIX.IO_Count;
       Masked_Signals   : in  POSIX.Signal_Masking;
       Options          : in  Message_Option_Set
         := Message_Option_Set (POSIX.Empty_Set));

For Receive, using an IN OUT parameter might make some sense,
since in general we have to parse the buffer as an array of octets
before we can determine the type to which we want to convert it.
However, in the case of Send, the in out parameter forces extra
shenanigans with unchecked conversions.

   procedure Send
      (Socket         : in  POSIX.IO.File_Descriptor;
       Buffer         : in  System.Address;
       Octets_To_Send : in  POSIX.IO_Count;
       Octets_Sent    : out POSIX.IO_Count;
       Masked_Signals : in  POSIX.Signal_Masking;
       Options        : in  Message_Option_Set
         := Message_Option_Set (POSIX.Empty_Set));

Suppose I have an Ada record Message that contains the message I want to
send.  If the parameter were in out of type Octet_Array (say), I would
have to do an unchecked conversion on a pointer type, or some such
trickery, to get an Octet_Array to send.  As it is, if I know the
record is contiguously laid out in memory (e.g., convention C),
I can just pass Message'Address to Send.

The case of iovecs is a bit different, since the array being
passed is an array of structs.  There, we decided to use IN OUT
parameters.

[BTW, where in the ARM does it specify that if X is a formal
parameter passed by reference X'Address is the address of the
actual parameter and not the address of the formal parameter
(i.e., the location where the address of the actual parameter is
stored)?]

| <<On the other hand, there are *some* C interfaces that pass
| pointers-to-strings, where a non-null value means "use this buffer", and
| a null value means "allocate a buffer that's big enough, and use that".
| I find such an interface ugly, but sometimes you have to interface to
| such a thing.
| >>
| Note that the Null_Parameter feature of DEC Ada (now reproduced in GNAT)
| allows precisely this capability (specification of a null pointer value for
| a by-reference parameter).

Yes, the POSIX interfaces have several such instances, where a null value
must be passed for special effect.  The GNAT extension is nice, but
is not acceptable for a standard API.

--Ted Baker

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

!section 4.6(16)
!subject object subtype must statically match designated subtype
!reference RM95-4.6 (16)
!reference 1998-15802.a Ted Baker  1998-2-25
!reference 1998-15803.a Norman H Cohen  1998-2-26
!reference 1998-15810.a Ted Baker  1998-2-27
!reference as: 1998-15815.a Robert Dewar 1998-2-28>>
!reference 1998-15816.a Ted Baker  1998-3-1
!from Bob Duff
!reference 1998-15817.a Robert A Duff  1998-3-2>>
!discussion

> We decided to use System.Address for octet arrays, when they
> are used as I/O buffers.  At the end the convincing reason was that
> in practice people will be using these (socket and XTI I/O)
> operations to transmit and receive objects of various user-defined
> types, treating them as octet sequences.

Sounds reasonable to me.  It's horribly low-level, of course, but the
programmer can always wrap it in generics or some such, to produce a
thicker binding, if so desired.

But now the situation looks a bit different to me -- a deliberate choice
to use the low-level 'Address-ish binding for good reasons, rather than
being painfully forced into that choice due to a language restriction.

> [BTW, where in the ARM does it specify that if X is a formal
> parameter passed by reference X'Address is the address of the
> actual parameter and not the address of the formal parameter
> (i.e., the location where the address of the actual parameter is
> stored)?]

One could argue that it follows from 6.4.1(10).  The formal and actual
denote two different views of the same object, and 'Address gives you
the address of the object -- there's no such thing as an address of a
view.

Anyway, even if you don't buy the above reasoning, it seems reasonable
to count on 'Address doing the sensible thing.  Returning the
address-of-the-address-of-the-actual is not sensible, and I can't
imagine any implementation doing it.  If they do, send them a bug
report!

> Yes, the POSIX interfaces have several such instances, where a null value
> must be passed for special effect.  The GNAT extension is nice, but
> is not acceptable for a standard API.

How about Randy's suggestion -- split it into two subprograms, one of
which has the special null behavior, and the other doesn't?  It makes
the binding a wee bit "thicker", but not unreasonably so.

- Bob

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

!section 4.6(16)
!subject object subtype must statically match designated subtype
!reference RM95-4.6 (16)
!reference 1998-15802.a Ted Baker  1998-2-25
!reference 1998-15803.a Norman H Cohen  1998-2-26
!reference 1998-15810.a Ted Baker  1998-2-27
!reference as: 1998-15815.a Robert Dewar 1998-2-28>>
!reference 1998-15816.a Ted Baker  1998-3-1
!reference 1998-15817.a Robert A Duff  1998-3-2
!from Dan Lehman
!reference 1998-15818.a Dan Lehman 1998-3-3>>
!discussion

TB [BTW, where in the ARM does it specify that if X is a formal
TB parameter passed by reference X'Address is the address of the
TB actual parameter and not the address of the formal parameter
TB (i.e., the location where the address of the actual parameter is
TB stored)?]

BD One could argue that it follows from 6.4.1(10).  The formal and actual
BD denote two different views of the same object, and 'Address gives you
BD the address of the object -- there's no such thing as an address of a
BD view.

And, Bob, you might recall that this subtle point arose in an ACVC
deliberation:

> |Note that formal parameters of a tagged type are not objects in their
> |own right; they are just views.  6.4.1(10).
>
>    Since 3.3(4) gives a somewhat different view, one might object. [sorry]
> Should this have an AI-ish note of explanation--to qualify 3.3(4) to mean
> "... formal parameter that is passed by copy ..."?
>
> ---Dan
> ------- *
>
> Yeah, I guess so.
>
> - Bob

=============================================================================

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

Questions? Ask the ACAA Technical Agent