From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,b14a804025dceb20 X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 2000-10-26 14:31:57 PST Path: supernews.google.com!sn-xit-02!sn-xit-03!supernews.com!xfer13.netnews.com!netnews.com!cpk-news-hub1.bbnplanet.com!cambridge1-snf1.gtei.net!news.gtei.net!inmet!not-for-mail From: Tucker Taft Newsgroups: comp.lang.ada Subject: Re: Constructors/Destructors in Ada95 Date: Thu, 26 Oct 2000 17:31:55 -0400 Organization: AverStar (formerly Intermetrics) Burlington, MA USA Message-ID: <39F8A2CB.CA319F5@averstar.com> References: <39EE160D.F0A2000@bigfoot.com> <39EF5431.BF4CD793@bigfoot.com> <39F0A6C7.E592AFFB@averstar.com> <39F4AE95.4DB04145@bigfoot.com> <39F6D201.73C006FA@acm.org> <8t6pi9$9s8$1@nnrp1.deja.com> <8t6vhc$fmb$1@nnrp1.deja.com> NNTP-Posting-Host: nebula.burl.averstar.com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-Trace: inmet2.burl.averstar.com 972595915 13056 141.199.8.77 (26 Oct 2000 21:31:55 GMT) X-Complaints-To: usenet@inmet2.burl.averstar.com NNTP-Posting-Date: 26 Oct 2000 21:31:55 GMT X-Mailer: Mozilla 4.75 [en] (X11; U; SunOS 5.7 sun4u) X-Accept-Language: en Xref: supernews.google.com comp.lang.ada:1585 Date: 2000-10-26T21:31:55+00:00 List-Id: mark.biggar@trustedsyslabs.com wrote: > ... > > One of the problems with this proposal (redefineing ":=") is that > you would have to define Initialize, Adjust and Finialize anyway > as you need them to implement value parameter passing, temporary > creation and function return values correctly. Each of those is > like assingment, but not exactly the same being, built out of the > three primitives in different ways. So it makes more sense to just > define the three primitives and have the compiler generate > standard usage sequences then to redefine ":=" and have strange > and hard to understand things happen. This is part of the reason we did not allow the user to directly define ":=". Another important reason has to do with assignment of composite objects (e.g. records and arrays) containing objects with user-defined assignment. One desirable feature is that the assignment for a record, for example, is defined in terms of the assignment of its individual components. Unfortunately, there are cases of record assignment in Ada where the left-hand-side doesn't contain a component that the right-hand-side does. This happens if the left-hand-side is an unconstrained record with discriminants, and the right-hand-side happens to have different values for the discriminants than the values of the left-hand-side. As a result of the assignment, some components of the left-hand-side may disappear, and some may come into existence. For example: type Rec(B : Boolean := False) is record X : Cool_Controlled_Type; case B is when True => Y : Fancy_Controlled_Type; when False => Z : Another_Controlled_Type; end case; end record; R1 : Rec; -- Defaults to B => False R2 : Rec(B => True); ... R1 := R2; -- R1.Z disappears, R1.Y is created, -- R1.X overwritten It would be tricky at best to define how or whether user-defined ":=" for Cool_, Fancy_, and Another_Controlled_Type should be used in the above case. However, with the user-defined operations broken down into Finalize and Adjust, it is relatively straightforward to specify what happens: R1.Z is finalized, R1.Y is adjusted after copying from R2.Y, and R1.X is first finalized, and then adjusted after copying from R2.X. One viable semantics would be to specify that user-defined assignment is used only for those cases where the component already exists, and is being overwritten, and finalize or adjust is used for the other cases. That could work, though it would prevent using block copy. With the current approach, block copy can be used to actually copy the "bits" from R2 to R1, so long as any appropriate finalizations are done before the copy, and any appropriate adjusts are done afterward. If the record has a bunch of non-controlled components, then being able to use block copy might be seen as an important advantage of the Ada 95 approach. Another nice feature of the current mechanism is that the compiler can create a single "whole record finalize" and another "whole record adjust" procedure, which are simply "roll ups" of the per-component finalize/adjust operations, possibly with an implicit "case" statement based on the current value of the discriminants. An assignment statement would then involve a call on the whole-record finalize, followed by a block copy, followed by a call on the whole-record adjust. (Also note that an explicit initialization in a declaration "looks like" an assignment statement, but it couldn't use the user-defined assignment, because the left-hand side isn't yet initialized. It really just needs a copy and adjust. No finalizes should be performed.) Creating an equivalent "whole-record-assign" rollup would certainly be possible, though the details of such a routine for a record type like "Rec" above would be pretty painful. You would compare the values of the discriminants of the left and right sides, and then depending on the various possibilities, one would do one of three things for each component: finalize LHS component, copy RHS into LHS and adjust, or user-defined-assign RHS into LHS. The order of doing this would be somewhat tricky, and there are sometimes "implicit" components that need copying as well. Finally, somebody has to do the constraint check when the left-hand side is *not* unconstrained, handle the case of self-assignment, handle the case of slice assignments (deciding between left-to-right or right-to-left based on relative start addresses) and there are issues of abort deferral, etc. Despite all the above "moaning and groaning," it still might be useful to allow user-defined assignment, even if it is only used in certain cases (e.g. LHS exists, and is initialized, and will still exist after the assignment). Presumably the user-defined assignment would take over the constraint check, and perhaps the check for self-assignment. I suppose it might be nice for the compiler to generate the check for self-assignment, since it is needed at most once for an assignment statement (it is not needed on each component), and it will often be possible to optimize it away. In most cases, the user-defined assignment would just be an optimization. However, because it would take over the constraint check, the user-defined assignment could also take on the job of implicit subtype conversion if desired. E.g., if you have a discriminated type like: type Text(Max : Natural) is record Data : String(1..Max); end record; a user-defined assignment routine could automatically pad or chop on assignment, rather than just complaining about mismatched discriminants. One final advantage of the Ada 95 approach has to do with maintenance. If the user provides the assignment operation, then presumably they have to individually assign each of the components. If a new component is added, there is no automatic handling of the new component, and it might be forgotten in the user-defined assignment operation. By contrast, with the finalize/adjust approach, the finalize for a record type doesn't need to call the finalize operation for each component -- that happens automatically. The user-defined finalize for a record type only needs to worry about finalizations over and above those required for the individual components. Ditto for adjust. I suppose for user-defined assignment, one could provide some way to get access to the underlying predefined assignment operation (which omits calls on finalize/adjust for the record type), so that one could use that to handle copying all the components, before or after some special work is done at the record level. E.g., one might save the value of some component of the LHS, then do the predefined assignment of the RHS into the LHS, and then do a deep copy of the new value of the component potentially reusing space allocated for the saved component value. This would presumably be more efficient than doing the finalize and adjust, which by necessity need to operate independently of one another. > > There's a reason that C++ has several types of constructors and in > many ways the Ada mechanism is simpler. Also, C++ doesn't have discriminants, at least not explicitly (users sometimes define structs with an array at the end that can be extended), so the problem of "composing" a struct assignment out of the assignment for the individual components is not as difficult for the compiler. > > -- > Mark Biggar > mark.biggar@trustedsyslabs.com -Tucker Taft -- -Tucker Taft stt@averstar.com http://www.averstar.com/~stt/ Technical Director, Commercial Division, AverStar (formerly Intermetrics) (http://www.averstar.com/services/IT_consulting.html) Burlington, MA USA