Version 1.4 of ai05s/ai05-0196-1.txt

Unformatted version of ai05s/ai05-0196-1.txt version 1.4
Other versions for file ai05s/ai05-0196-1.txt

!standard 6.4.1(13)          10-02-04 AI05-0196-1/02
!class binding interpretation 10-02-03
!status Amendment 2012 10-04-02
!status ARG Approved 10-0-0 10-02-28
!status work item 10-02-03
!status received 09-12-09
!priority Medium
!difficulty Easy
!qualifier Omission
!subject Null exclusion checks for 'out' parameters
!summary
Null exclusion checks are not made for OUT parameters when evaluating the actual parameters.
!question
Does the following program raise Constraint_Error? (No.)
procedure M is type Integer_Access is access all Integer;
procedure X (Y : out not null Integer_Access) is begin Y := new Integer; end X;
A : Integer_Access; -- initially null begin X (A); -- Raise Constraint_Error here? end M;
That is, when passing an OUT mode parameter, is the implementation supposed to do a not-null check on the way in? (No.)
!recommendation
(See summary.)
!wording
Modify 6.4.1(13):
For an access type, the formal parameter is initialized from the value of the actual, without [a constraint check]{checking that the value satisfies any constraint or any exclusion of the null value};
!discussion
It would be weird and unfriendly if the prior value of the actual parameter mattered for an OUT parameter. There is no guarantee that an OUT parameter of an access type satisfies any access subtype constraint that applies to the formal, so there seems no reason to expect it to satisfy any null exclusion that might apply.
!corrigendum 6.4.1(13)
Replace the paragraph:
For an access type, the formal parameter is initialized from the value of the actual, without a constraint check;
by:
For an access type, the formal parameter is initialized from the value of the actual, without checking that the value satisfies any constraint or any exclusion of the null value;
!ACATS Test
Create an ACATS C-test to check that an example like the one in the question does not raise Constraint_Error.
!appendix

From: Bob Duff
Sent: Wednesday, December 9, 2010  4:49 PM

Does the following program raise Constraint_Error?

procedure M is
   type Integer_Access is access all Integer;
   procedure X (Y : out not null Integer_Access) is
   begin
      Y := new Integer;
   end X;
   A : Integer_Access; -- initially null begin
   X (A); -- Raise Constraint_Error here?
end M;

That is, when passing an OUT mode parameter, is the implementation supposed to
do a not-null check on the way in?

I think the relevant paragraph is 6.4.1(13):

        13    For an access type, the formal parameter is initialized from the
              value of the actual, without a constraint check;

It goes out of its way to skip the constraint check, but it doesn't say to skip
the not-null check.  On the other hand, it doesn't say that there IS a not-null
check (and implementations are not supposed to invent checks that the RM doesn't
explicitly call for). I think it should be explicit, one way or 'tother.

GNAT currently raises C_E for the above example.  Some of us at AdaCore find
that confusing, because the point of procedure X is to initialize the actual.
Others at AdaCore would find the opposite rule confusing, because a "not null"
object could be null.  I'm on the fence -- I can see both sides of that
argument.

And just before sending this, I notice that some of us have changed their mind!
;-)

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

From: Tucker Taft
Sent: Wednesday, December 9, 2010  5:03 PM

As Bob mentions, paragraph 6.4.1(13)
says no constraint check, but doesn't mention null-exclusion checks.

But it would be weird in my view, and pretty unfriendly, if the prior value of
the actual parameter mattered.  Note that there is no guarantee that an OUT
parameter of an access type satisfies any access subtype constraint that applies
to the formal, so there seems no reason to expect it to satisfy any null
exclusion that might apply.

So I would say, don't check.  Clearly the RM needs some clarification here.

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

From: Pascal Leroy
Sent: Thursday, December 10, 2010  12:23 AM

>I think the relevant paragraph is 6.4.1(13):
>
>   13    For an access type, the formal parameter is initialized from the
>         value of the actual, without a constraint check;
>
> It goes out of its way to skip the constraint check, but it doesn't say
> to skip the not-null check.  On the other hand, it doesn't say
> that there IS a not-null check (and implementations are not
> supposed to invent checks that the RM doesn't explicitly call for).
> I think it should be explicit, one way or 'tother.

It has been the intent all along that constraints and null exclusion work
similarly, so I think passing in null is just fine.

In fact, I can't find in the RM a definition of the phrase "constraint check",
so it's unclear to me if the Access_Check related to null exclusion is or is not
a "constraint check".  It might be better to rephrase this rule using the term
"satisfies".

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

From: Bob Duff
Sent: Thursday, December 10, 2010  1:53 PM

> It has been the intent all along that constraints and null exclusion
> work similarly, so I think passing in null is just fine.

OK.

> In fact, I can't find in the RM a definition of the phrase "constraint
> check", so it's unclear to me if the Access_Check related to null
> exclusion is or is not a "constraint check".

The term "constraint check" is rather informal.  I think its meaning was crystal
clear before we invented null_exclusions.

Now it's less clear.  But a null_exclusion is not a constraint (for obscure
language-legalistic reasons), so I'd say "constraint check" does not include the
not-null check on null_exclusions.

>...It might be better to rephrase this rule  using the term
>"satisfies".

I don't quite see how to do that -- can you show us some wording that uses
"satisfies"?

I was thinking "..., without a constraint check or null_exclusion check". Still
informal, but clear enough.

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

From: Randy Brukardt
Sent: Thursday, December 10, 2010  2:21 PM

> I don't quite see how to do that -- can you show us some wording that
> uses "satisfies"?

I'm not Pascal, but how about:

For an access type, the formal parameter is initialized from the value of the
actual, without [a constraint check]{checking that the value satisfies any
constraint or any null_exclusion};

Humm, safisfies isn't defined for null exclusions. Turn that around:

For an access type, the formal parameter is initialized from the value of the
actual, without [a constraint check]{checking the value against any
null_exclusion or that the value satisfies any constraint};

Longer, but more formal.

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

From: Pascal Leroy
Sent: Thursday, December 10, 2010  2:21 PM

I don't quite see how to do that -- can you show us some wording that
uses "satisfies"?

I was thinking "..., without a constraint check or null_exclusion check".
Still informal, but clear enough.

I was thinking of replacing the part after the comma in 6.4.1(13) by something
like:

"No check is made that the actual satisfies the constraints or null exclusion of
the formal subtype."

But then my wording-crafting skills are a bit rusty these days...

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

From: Pascal Leroy
Sent: Thursday, December 10, 2010  2:26 PM

> Humm, safisfies isn't defined for null exclusions. Turn that around:

It is, last sentence of 3.10(15/2).

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

From: Randy Brukardt
Sent: Thursday, December 10, 2010  2:43 PM

You are right, I've surprised that 4.6(51/2) didn't take advantage of that.
(That's what I used as a pattern.)

So my suggestion should have been:

For an access type, the formal parameter is initialized from the value of the
actual, without [a constraint check]{checking that the value satisfies any
constraint or any exclusion of the null value};

(echoing the wording of 3.10(15/2)).

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

From: Tucker Taft
Sent: Thursday, December 10, 2010  2:48 PM

"satisfies" *is* defined for null exclusions.  See last sentence of 3.10(15/2).
So I think the simplest might be:

   For an access type, the formal parameter is initialized from the value of the
   actual, without [a constraint check]{checking whether the value satisfies any
   constraint or null_exclusion};

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

From: Pascal Leroy
Sent: Thursday, December 10, 2010  4:08 PM

Technically you don't satisfy a null_exclusion (there may not be any such
syntactic construct in sight), you satisfy "an exclusion of the null value".

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

Questions? Ask the ACAA Technical Agent