From: Hibou57 (Yannick Duchêne) on
On 12 fév, 00:08, Robert A Duff <bobd...(a)shell01.TheWorld.com> wrote:
> Extended return statements are important in the limited case,
> because you often want to say something like "Result.X := ...;".
> And as you discovered, aggregates aren't allowed for protected
> or task types (which was probably a language design mistake).
I agree with this in some way, as protected are largely handled like
records. Further more, when you've made a syntactic while writing the
declaration or the body of a protected, then GNAT, most of times
points the error using the term "record" in the message (by the way,
with respect to the way the language is defined, I feel this kind of
message is not well suited, these may be disturbing for some users).

On the other hand, why would someone want to initialize any thing in a
protected ? The private part being only visible to the protected it-
self, this would not make sense. Well, sure it would be useful to
return a protected where a class-wide type is expected as the return
result : the language requires an initialization here, thus the idea
of an aggregate for protected and task in this purpose, in order to be
able to initialize this class-wide type. But this should be an empty
aggregate. What is needed, is not really an aggregate, but something
to initialize an entity of class-wide type.

Better than an aggregate for protected and task, there should be
something acting like an empty aggregate, which would be to be used as
an initializer for protected and task only.
From: Hibou57 (Yannick Duchêne) on
On 12 fév, 00:08, Robert A Duff <bobd...(a)shell01.TheWorld.com> wrote:
> Extended return statements are not so important for nonlimited types,
> but they do come in handy in that case, too.
While this may be useful, if it was, to have a way to return none-
limited as built-in-place, for efficiency purpose (just suggesting
this be to investigated, I do not assert this could surely be done
like this and as-is).
From: Hibou57 (Yannick Duchêne) on
On 12 fév, 00:24, Robert A Duff <bobd...(a)shell01.TheWorld.com> wrote:
> Well, I don't find it "graceful" that single-element positional
> aggregates are not allowed.  And zero-element ones.  I think
> it's just bad language design.
It seems you are suggesting the ambiguity should be resolved
semantically. Why not :)
From: Alex R. Mosteo on
Adam Beneschan wrote:

> On Feb 11, 11:10 am, Robert A Duff <bobd...(a)shell01.TheWorld.com>
> wrote:
>> Adam Beneschan <a...(a)irvine.com> writes:
>> > But more simply, as I understand it: (1) When you have an extended
>> > return, the return object is used as the anonymous object that holds
>> > the function result at the point of the function call, so it's not
>> > finalized until the caller is done with the anonymous object; and (2)
>> > when the object is built in place, the anonymous object "mutates into"
>> > the new object and is not finalized (7.6(17.7/3)). So yes, no
>> > finalization should be done until X goes out of scope.
>>
>> Just to be clear: There's nothing particularly special about
>> extended return statements, other than the fact that they
>> provide a name for the result.
>
> That last is an important distinction, however. A function call
> involves (conceptually) an anonymous object. For a normal return (for
> a non-limited type):
>
> return Some_Expression;
>
> Some_Expression is computed and then assigned into the anonymous
> object. This assignment involves an Adjust. Then, at some point,
> whatever objects went into creating Some_Expression will get finalized
> when the function exits. If Some_Expression is a local variable, for
> instance, that variable will get finalized. If some other temporary
> needs to be created in order to hold the value of Some_Expression,
> that temporary will be finalized.
>
> For an extended return,
>
> return R : T;
>
> R is not a local variable, and it isn't "assigned" into the anonymous
> object; thus, there's no Adjust, and R is not finalized when the
> function returns (but the anonymous object will be finalized later,
> except when it mutates into some other object). I think that's the
> point of the nasty language in 3.10.2(10.1). Which is another way of
> saying that R is a name for the result (as you said), not a distinct
> object that gets copied to the result. I thought it would be helpful
> to point it out---not to you, but to other readers. It's hardly a
> trivial difference, and it's an important one to understand when
> adjusts and finalizations are involved. Anyway, I hope this helps
> someone.

I remember an old thread I started on return by reference. My question then
was if gnat was clever enough to optimize away copies in returned values
used as constants, specifically using the container library. The answer
empirically found was that it wasn't.

While not the same thing as a C++ return by constant reference, if I
interpret you correctly, this kind of return X : T; removes one copy of the
object in the returning machinery, by using the destination as in-place
receptacle, right? If so, I wonder if it's worth the attempt to use this in
some speed critical code.
From: Adam Beneschan on
On Feb 12, 1:27 am, "Alex R. Mosteo" <alejan...(a)mosteo.com> wrote:

> I remember an old thread I started on return by reference. My question then
> was if gnat was clever enough to optimize away copies in returned values
> used as constants, specifically using the container library. The answer
> empirically found was that it wasn't.
>
> While not the same thing as a C++ return by constant reference, if I
> interpret you correctly, this kind of return X : T; removes one copy of the
> object in the returning machinery, by using the destination as in-place
> receptacle, right? If so, I wonder if it's worth the attempt to use this in
> some speed critical code.

Maybe. Doing it this way could remove one copy, according to the
language semantics. However, the compiler can of course generate any
code it wants, if it has the effect that the language semantics
demand.

I did try this with one compiler:

function Func1 return Rec is
Result : Rec;
begin
Result.Component1 := <blahblah>;
Result.Component2 := <blahblah>;
return Result;
end;

function Func2 return Rec is
begin
return Result : Rec do
Result.Component1 := <blahblah>;
Result.Component2 := <blahblah>;
end return;
end Func2;

With optimization turned off, Func2 did generate one less copy.
However, the generated code passed the address of a "result object" as
a parameter to the functions, and this means Func2 would be using
indirection through this address to set the components, while Func1
would be setting them on the local stack frame. Whether this
indirection adds any cycles, I don't know. I'd guess that it
wouldn't, but this could depend on the processor.

But, assuming that there are no controlled components, there's nothing
preventing the compiler from generating the same code for Func1 as for
Func2, and eliminating the extra copy. So I guess that using extended
return might be worth a try---try it both ways, and see if the
compiler generates faster code.

If there are controlled components, then the semantics are different,
because Func1 will have to assign Result to the "result
object" (requiring an "adjust" operation) and then finalize Result
(requiring a "finalize" operation). The language gives compilers
permission to remove adjust/finalize pairs in some cases, but I don't
know if this is one of those cases. If not, then this is a case where
extended return will definitely benefit you.

-- Adam