Version 1.1 of ai12s/ai12-0219-1.txt

Unformatted version of ai12s/ai12-0219-1.txt version 1.1
Other versions for file ai12s/ai12-0219-1.txt

!standard B.1(38.1/3)          17-04-07 AI12-0219-1/01
!standard B.3(69/2)
!standard B.3(70)
!class binding interpretation 17-04-07
!status work item 17-04-07
!status received 16-12-22
!priority Low
!difficulty Easy
!qualifier Omission
!subject Clarify C interfacing advice
!summary
An Ada "in" parameter most closely matches "const T*" in C code.
!question
Some Ada users have taken the advice in B.3(69-70) to mean that it is OK to modify an Ada "in" parameter in an imported routine. This clearly violates B.1(38.1/3). An Ada "in" parameter corresponds most closely with "const T*" rather than just "T*". Shouldn't the advice mention this? (Yes.)
!recommendation
(See Summary.)
!wording
Modify B.1(38.1/3):
It is the programmer's responsibility to ensure that the use of interfacing aspects does not violate Ada semantics; otherwise, program execution is erroneous.{ For example, passing an object with mode in to imported code that modifies it causes erroneous execution. Similarly, calling an imported subprogram that does is not pure from a pure package causes erroneous execution.}
Modify B.3(69/2):
* An Ada parameter of a record type T, of any mode, other than an in parameter
of a type of convention C_Pass_By_Copy, is passed as a t* argument to a C function, where t is the C struct corresponding to the Ada type T.{ In the case of an Ada parameter of mode in, use of the const modifier (that is, const t*) is recommended.}
Modify B.3(70):
* An Ada parameter of an array type with component type T, of any mode, is
passed as a t* argument to a C function, where t is the C type corresponding to the Ada type T.{ In the case of an Ada parameter of mode in, use of the const modifier (that is, const t*) is recommended.}
[Editor's note: I'd prefer breaking the above into 4 bullets, because these are defining "correspondences", not specifically how imported C code should be written. Most C code isn't under control of the Ada programmer anyway, so its unclear who that recommendation is for anyway. My suggestion:
Replace B.3(69/2) with:
* An Ada in parameter of a record type T, where T does not have convention C_Pass_By_Copy,
is passed as a const t* argument to a C function, where t is the C struct corresponding to the Ada type T. This is equivalent to a t* argument if the C code does not modify the argument; otherwise execution may be erroneous (see B.1).
An Ada parameter of a record type T, other than a parameter of mod in, is passed as a t
argument to a C function, where t is the C struct corresponding to the Ada type T.
Replace B.3(70) with:
An Ada in parameter of an array type with component type T is passed as a const t argument
to a C function, where t is the C type corresponding to the Ada type T. This is equivalent to a t* argument if the C code does not modify the argument; otherwise execution may be erroneous (see B.1).
* An Ada parameter of an array type with component type T, of any mode other than mode in, is passed
as a t* argument to a C function, where t is the C type corresponding to the Ada type T.
End Editor's note.]
!discussion
We add some examples to B.1(38.1/3) to try to illustrate what it is talking about. This is a very important rule to implementers, as it constrains what an interfaced routine can do. Users need to be aware of the consequences.
!ASIS
No ASIS effect.
!ACATS test
No ACATS test needed, as the change is purely on the C side of the code. One could imagine changing the C code in some of the tests to follow this advice (to illustrate best practice), but it would make no operational change to the existing tests. (They're not erroneous as it is, and sometimes an IN parameter is the best match to an existing C interface.)
!appendix

From: Steve Baird
Sent: Thursday, December 22, 2016  1:09 PM

A user had the incorrect impression that it is ok to bind an imported (on
the Ada side) convention-C subprogram with an in-mode parameter of an array
type to a routine written in C which modifies that parameter (the actual
parameter in all calls was a variable).

This is clearly a mistake and is covered by RM B.1 (38.1/3):
    It is the programmer's responsibility to ensure that the use of
    interfacing aspects does not violate Ada semantics; otherwise,
    program execution is erroneous.

Nonetheless, it was pointed out in the ensuing discussion that it might be
helpful if B.3(69-70) recommended (or at least mentioned) using "const T*"
instead of "T*" in the case of an in-mode Ada parameter of an array or record
type.

What would folks think of appending the following sentence (displayed with
appropriate fonts) at the end of both B.3(69/2) and B.3(70):

   In the case of an Ada parameter of mode in,
   use of the const modifier (i.e., const t*) is recommended.

? Is there a better way to express this that doesn't involve two copies of the
same sentence?

We could also do something similar in the case of an access-to-constant
parameter type, but that's not the topic of this message.

P.S. I hope I got the "const T*" vs. "T* const" distinction right in the above.

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

From: Tucker Taft
Sent: Thursday, December 22, 2016  3:05 PM

> ... What would folks think of appending the following sentence 
> (displayed with appropriate fonts) at the end of both
> B.3(69/2) and B.3(70):
>
>   In the case of an Ada parameter of mode in,
>   use of the const modifier (i.e., const t*) is recommended.
>
> ? Is there a better way to express this that doesn't involve two 
> copies of the same sentence?

I would just start the sentence in the second occurrence:

    "As above, in the case ..."

since it is in the immediate following paragraph.

I would also suggest we add somewhere a note saying that if an imported
routine modifies a parameter declared with mode IN, it can lead to
erroneous execution, with a reference to the more general rule.

> We could also do something similar in the case of an access-to-constant
> parameter type, but that's not the topic of this message.
>
> P.S. I hope I got the "const T*" vs. "T* const" distinction
> right in the above.

Yes, you got it right.  In this case, "const t* const" would also make sense,
but the more  important "const" is the first one.

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

From: Steve Baird
Sent: Thursday, December 22, 2016  3:34 PM

> I would just start the sentence in the second occurrence:
>
>     "As above, in the case ..."
>
> since it is in the immediate following paragraph.
>

Sounds good.

> I would also suggest we add somewhere a note saying that if an 
> imported routine modifies a parameter declared with mode IN, it can 
> lead to erroneous execution, with a reference to the more general rule.

Also sounds good.

Perhaps "somewhere" could be at the point of the more general rule (i.e. the
Erroneous Execution section of B.1). We could (in redundant text) give a
couple of examples to illustrate the consequences of this rule.

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

From: Tucker Taft
Sent: Thursday, December 22, 2016  3:57 PM

>> ... I would also suggest we add somewhere a note saying that if an 
>> imported routine modifies a parameter declared with mode IN, it can 
>> lead to erroneous execution, with a reference to the more general rule.
>
> Also sounds good.
>
> Perhaps "somewhere" could be at the point of the more general rule 
> (i.e. the Erroneous Execution section of B.1).
> We could (in redundant text) give a couple of examples to illustrate 
> the consequences of this rule.

Yes, that might be helpful in making this one-sentence paragraph a bit clearer.

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

From: Randy Brukardt
Sent: Friday, April 7, 2016  7:38 PM

...
>What would folks think of appending the following sentence (displayed 
>with appropriate fonts) at the end of both B.3(69/2) and B.3(70):
>
>   In the case of an Ada parameter of mode in,
>   use of the const modifier (i.e., const t*) is recommended.

I'm writing this thread up, and it strikes me that the above wording is not a
good fit for the style of the rest of the implementation advice.

In particular, this section is written to specify correspondences between Ada
and C, without making any inference as to which side comes first. The above is
written as if the C code is being written second (which is the unusual case in
my experience). Usually the Ada programmer is matching some existing C code.

With that in mind, I'd probably write the above reversed, something like:

Care should be taken in selecting the mode of the parameter in this case; in
particular, mode *in* should be used only if the C code uses the const
modifier (that is, const t*) or if the C code does not modify the parameter;
otherwise execution may be erroneous (see B.1).

[Aside: We never use "e.g." or "i.e." in Standard wording. Please use "for
example" or "that is"... End lecture.]

This is better because it matches the way this section is typically used, and
it manages to work in a cross-reference to a rule that most Ada programmers
never have seen (and is critical). This is lousy because it's a run-on
sentence, and because it still isn't in the style of the actual bullets. And
both of these solutions seem to be only worrying about imported C routines;
what about Ada routines exported to C?? (To be far, much of the existing
wording already has this problem. This is supposed to be about
"correspondences", direction of passing shouldn't enter into it.)

The best solution would be to properly split the bullet to always use the
modifier for the in parameter case (and add a sentence suggesting that t* can
be used instead with care):

* An Ada in parameter of a record type T, where T does not have convention
  C_Pass_By_Copy, is passed as a const t* argument to a C function, where t
  is the C struct corresponding to the Ada type T. This is equivalent to a
  t* argument if the C code does not modify the argument; otherwise execution
  may be erroneous (see B.1).
* An Ada parameter of a record type T, other than a parameter of mod in, is
  passed as a t* argument to a C function, where t is the C struct
  corresponding to the Ada type T.

And likewise for the array case:

* An Ada in parameter of an array type with component type T is passed as a
  const t* argument to a C function, where t is the C type corresponding to
  the Ada type T. This is equivalent to a t* argument if the C code does not
  modify the argument; otherwise execution may be erroneous (see B.1).
* An Ada parameter of an array type with component type T, of any mode other
  than mode in, is passed as a t* argument to a C function, where t is the C
  type corresponding to the Ada type T.

In all of these, I don't like the phrase "...is passed as...to a C function",
because for export it is going the other way but we're using the same
correspondences (at least I hope so!), and for access-to-subprogram convention
it could be going either way. But that's probably not worth fixing 23 years in
(this section dates back 1994 drafts of Ada 9x).

Should we go all the way here (as in my last suggestion), or is there some
better wording than I've been able to come up with??

...
> > Perhaps "somewhere" could be at the point of the more general rule 
> > (i.e. the Erroneous Execution section of B.1).
> > We could (in redundant text) give a couple of examples to illustrate 
> > the consequences of this rule.
> 
> Yes, that might be helpful in making this one-sentence paragraph a bit 
> clearer.

Unfortunately, no one suggested what other example(s) might be relevant. I
recall that this rule has come up repeatedly in discussion of other AIs, but
I'm not going to go looking for those. The Duff technique of defeating Pure
restrictions came to mind after much griping, so I used that, but perhaps
someone has a better example.

It is the programmer's responsibility to ensure that the use of interfacing
aspects does not violate Ada semantics; otherwise, program execution is
erroneous.{ For example, passing an object with mode in to imported code that
modifies it causes erroneous execution. Similarly, calling an imported
subprogram that does is not pure from a pure package causes erroneous
execution.}

Better examples/wording welcome.

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

Questions? Ask the ACAA Technical Agent