On Wed, 6 Apr 2016,
ah...@marriott.org wrote:
>> In the annotated RM, in the section concerning Null Procedures, it says
>> "There are no null functions because the return value has to be
>> constructed somehow; a function that always raises Program_Error doesn't
>> seem very useful or worth the complication" If there are no null
>> functions because a return value has to be constructed then surely the
>> same applies to null procedures that have out parameters. These too
>> should be prohibited [...]
>
>This seems to be right. It does not make much sense to allow the
>declaration of
>
> procedure X(Formal: out T) is null;
>
>while prohibiting the declaration of
>
> function Y return R is null;
Playing Devil's Advocate here, the latter always raises Program_Error; if
you really meant that there are better ways (see below). The former does
nothing at all other than deinitialize its actual parameter. So they're not
really the same thing.
> The point is, you can neither call X nor Y. Semantically, both statements
>
> X(Actual);
> Actual := Y;
>
>are equally useless, or at least their effect is equally undefined.
No, both are very well-defined. And there is nothing wrong in either case
with making a call (so long as Actual is not used afterwards.
I have *lots* of procedures for which one or more actuals are meaningless
after the call, and better not be touched. (The case where *all* parameters
are like that is of course pathological, but to have one of of several is
pretty common.)
>Allowing the declaration of X, but prohibiting the declaration of Y is
>inconsistent.
Maybe, but there is a big difference: allowing the declaration of Y is new
feature that would be a lot of work for implementers and is 100% useless.
(Again, there is a better way to write a function that always raises
Program_Error, see below.) Whereas *disallowing* the declaration of X would
be additional work for implementers (and now would also be incompatible).
The null procedure feature itself has many obvious uses, and you are talking
about a tiny corner case.
I can see that it might have made sense to disallow out parameters when the
feature was defined, but I don't think we ever thought of it. As I noted in
another message, a null procedure is semantically just a short-hand for
"begin null; end;" and I don't think we considered having *different*
Legality Rules for it.
And it's definitely too late now; breaking existing code (especially
interface declarations) for this issue seems like a non-starter. Such a rule
would do very little to reduce this problem (it happens to me periodically
for normal procedures), so the incompatibility would just not be tolerable.
And of course, changing the rules to raise Program_Error, as the OP
suggested, would be even more of a nonstarter as a runtime incompatibility.
No one would want programs that work fine today start raising Program_Error
because some object that is never used got de-initialized. We had a similar
case that involved a real semantic problem with access types, and we
eventually decided to make it illegal (rather than raise Program_Error or
make it erroneous) as the best of a bad set of choices (Program_Error was
the least liked of all). [We did choose Program_Error for a similar case,
but that was because we assumed that there were no such programs as "scalar
with Default_Value" was first added in Ada 2012, not so for things in Ada 83
(or Ada 2005).]
Ada 83 got the handling of uninitialized objects wrong (including this case
of out parameters) for a language which defaults to "safe". We're pretty
much stuck with that today, changes would break almost all existing code.
That's too bad, but I guess it just shows that no language is perfect.
>If people really think they need to declare something like the above
>procedure X, a revised Ada standard could allow declarations such as
>
> procedure X(Formal: T) is raise;
>
>and
>
> function Y return T is raise;
>
>where "is raise" stands for "raise Program_Error". That may sometimes come
>handy in the context of inheritance, or so.
(1) The above null procedure X does not and would never raise Program_Error,
so the first part of this doesn't make any sense.
(2) The latter can be written in current Ada 2012: (that is, with TC1
implemented)
function Y return T is (raise Program_Error);
which is both clearer and hardly any longer. I can't imagine why we'd add
another feature just to save two parens and a name (that it actually helps
to make explicit).
Randy.