Prev: Tiny mistaken on an AdaPower page
Next: Initialization and Finalization of limited object "returned"by a function
From: Hibou57 (Yannick Duchêne) on 12 Feb 2010 00:37 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 12 Feb 2010 00:39 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 12 Feb 2010 00:41 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 12 Feb 2010 04:27 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 12 Feb 2010 11:43
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 |