!standard 07.06.01 (04) 99-09-15 AI95-00193/06 !standard 07.06.01 (16) !class binding interpretation 97-08-19 !status Corrigendum 2000 99-07-27 !status WG9 approved 99-06-12 !status ARG approved (with editiorial changes) 6-0-3 99-03-25 !status work item 98-04-02 !status received 97-08-19 !priority High !difficulty Hard !qualifier Clarification !subject Initialize, Adjust, and exceptions !summary For a controlled object (including a component) that is initialized explicitly by assignment (possibly to an enclosing object), if its Adjust procedure is invoked but then fails by propagating an exception, it is not specified by the language whether the object is finalized. If the object is initialized by assignment from an aggregate, its Adjust procedure is not invoked (per AI-00083 and AI-00197), but it is finalized if and only if the initialization is successful. If it is initialized by assignment from something other than an aggregate, but its Adjust procedure is not invoked at all because initialization fails before that point, then the object is not finalized. For an object that is initialized by default, the object is not finalized unless default initialization completes successfully, i.e. without propagating an exception. For an Adjust invoked as part of initialization, if it propagates an exception, no other adjustments need be performed prior to raising Program_Error. !question If an object that is initialized by assignment fails during an Adjust operation, should the object nevertheless be finalized? (This AI recommends that this be unspecified.) !recommendation Paragraph 7.6.1(4) says: ... each object ... is finalized if the object was successfully initialized and still exists. This is relaxed for objects that are initialized by assignment when an Adjust propagates an exception. For such objects, the object may be finalized so long as the Adjust operation is invoked, even if it propagates an exception. It must be finalized if the Adjust operation completes successfully. For objects which are initialized by default, no change in the wording is proposed; such objects are finalized if and only if default initialization completes without propagating an exception. The definition of "adjustments due to be performed" should be relaxed for an assignment operation that is part of initialization, thereby allowing initialization to be abandoned as soon as any Adjust fails. For an assignment statement, it is important that all adjustments be performed, even if one fails, because all controlled subcomponents are going to be finalized. !wording (See corrigendum.) !discussion When an object (including a component) is initialized by an assignment other than from an aggregate, the Adjust operation is invoked. If this operation propagates an exception, then other Adjust operations that are already due to be performed are performed, and then Program_Error is raised. What this means is that if you have a composite object which is initialized by an assignment from something other than an aggregate, and it has multiple controlled parts, then if one of the Adjust operations fails, the others are still invoked. Clearly those parts for which Adjust succeeds should be finalized per 7.6.1(4). However, 7.6.1(4) implies that the ones for which Adjust fails should not be finalized. However, for implementations that "bundle" all of the Adjust operations for all controlled parts of a composite type into a single "adjust-whole-object" procedure, it is burdensome to keep track of which parts failed and which succeeded, and only finalize those whose Adjust succeeded. Note that if some of the Adjust operations had failed in an assignment statement, all parts would ultimately still be finalized when the master is left. One of the important goals of the finalization model with respect to exceptions (paragraphs 7.6.1(14-18)) is that if one controlled abstraction fails by raising an exception in Adjust or Finalize, this failure should not spread to other unrelated controlled abstractions. Even when one composite object happens to have two controlled parts, one from the "failed" abstraction and one from the "still-good" abstraction, the "still-good" abstraction should still have Adjust and Finalize called the appropriate number of times to keep reference counts in sync, avoid dangling pointers, etc. Given this goal, the "bundling" of Adjust operations, and the correspondence with assignment statements, it seems best to allow that, so long as the Adjust routine has been invoked on an object being initialized, Finalize may be invoked on the object. On a somewhat separate issue, the notion of adjustments "due to be performed" (7.6.1(16)) need not apply to initialization by assignment. So long as a subcomponent is not going to be finalized, it need not be adjusted, even if it is initialized as part of an enclosing composite assignment operation for which some adjustments are performed. On the other hand, for an assignment that is part of an assignment statement, it is important that all adjustments be attempted, even if some of them fail, since all subcomponents are going to be finalized. This relaxation for adjustments that occur during initialization means that an initialization may be abandoned as soon as any Adjust fails, so long as those components which have never been adjusted are not finalized. !corrigendum 7.06.01(16) @drepl @xbullet @dby @xbullet !ACATS test This ruling explicitly makes some behavior unspecified. Therefore, no test is possible (It isn't possible to test unspecified behavior). !appendix !section 7.6.1(4) !subject Classwide Adjust and exceptions !reference RM95 7.6.1(4,16) !from Tucker Taft 97-07-25 !reference 1997-15759.a Tucker Taft 1997-7-25>> !discussion To support (explicit) initialization and assignment of classwide objects, our compiler generates an "Adjust_Whole_Object" routine for every non-limited tagged type. We dispatch to the appropriate one based on the tag of the classwide value being adjusted. It now appears we need to create two "Adjust_Whole_Object" routines, one for use in initialization, and one for use in assignment. Before we launch off on that additional work, I wanted to confirm my RM interpretation with others. BACKGROUND The Adjust_Whole_Object routine the compiler generates for a tagged type calls the user-defined Adjust routine of each controlled part of the type in the appropriate order, handles any exception and sets a flag but keeps going, and then at the very end, if the exception flag is set, raises Program_Error. The Adjust_Whole_Object routine is called with aborts deferred, either as part of initializing a classwide object by copy, or as part of a classwide assignment statement. In the case of initialization, we "register" the whole object for finalization (we have a Finalize_Whole_Object routine which will clean it up) only if the Adjust_Whole_Object succeeds. THE PROBLEM The problem is, if the Adjust_Whole_Object propagates Program_Error, then we don't register the whole object for finalization. We also don't register any part of the object for finalization, even those parts that were successfully adjusted, since we don't have any record of which parts succeeded versus which parts failed. This seems to violate the requirement of 7.6.1(4) which says that any object that is successfully initialized must be finalized. There seems to be no problem with Adjust_Whole_Object for the purposes of an assignment statement, because there is no need to keep track of which parts failed. All the parts have, presumably, already been registered for cleanup. The straightforward solution to this problem is to have a separate Adjust_Whole_Object_For_Initialization routine for each tagged type, which rather than just raising Program_Error when one or more parts fail to adjust, will also finalize any parts that were successfully adjusted before raising Program_Error. THE QUESTION Is there some way to have a single Adjust_Whole_Object routine per tagged type? One possibility is to go ahead and register the whole object for finalization if at least one part succeeds, and then live with the fact that we are going to finalize parts whose Adjust failed. That could happen as a result of an assignment statement anyway, and the only thing being corrupted is a part that was already "hosed" to begin with. Another possibility is to leave things as we have them now, which means no part is finalized if any parts fail. The problem with that is that one messed up controlled abstraction can have the effect of progressively messing up any other controlled abstraction, just by both being used as components of the same object. The "finalize-all-if-any-succeeds" therefore seems better to me than "finalize-none-if-any-fails" approach, but of course neither matches 7.6.1(4) which says "finalize-only-what-succeeds". In the spirit of AI95-179, the ARG might say that exceptions inside Adjust or Finalize are bad news anyway, and we should permit some relaxation of 7.6.1(4) in one direction or the other. Alternatively, the ARG says that the independence of controlled abstractions is quite important, and we should minimize failure coupling between them even if they appear as components of the same object, and hence stick with the exact 7.6.1(4) approach. Comments? -Tuck P.S. I think the ada-comment midnight forwarding is fixed, but I CC'ed "arg95" just in case. -T **************************************************************** !section 7.6.1(4) !subject Classwide Adjust and exceptions !reference RM95 7.6.1(4,16) !reference 1997-15759.a !from Bob Duff !reference 1997-15761.a Robert A Duff 1997-7-28>> !discussion Coincidentally, at Rational we recently came across the same issue. We came to the conclusion that if some subcomponent's Adjust fails, we should finalize the whole record, including the failed component. This seems better than skipping some finalizations. The reason for all these complicated rules about exceptions during adjust/finalize (C++ is vastly simpler, for the compiler writer, in this regard, by the way) is so that one broken abstraction can't "infect" another abstraction. In the case we're talking about here, one subcomponent is broken, and it doesn't really matter whether we finalize it or not -- the compiler has no way of knowing whether the Adjust failed before or after doing something that requires cleanup. Or in the middle. The programmer of each abstraction really has to either put an exception handler inside Adjust, or else prove that exceptions can't happen. Once Program_Error comes flying out of Adjust, there's really no way to tell what went wrong. It seems to me that if we're going to stick to this principle, we should stick to it. No point in saying, well, in a few cases, one broken abstraction can infect another. It's like saying there's just a small hole in the dike. On the other hand, it's OK for the broken abstraction to get more broken -- it's OK for Finalize to be called when Adjust-during-initialization failed. Having two Adjust_Whole_Object procedures is possible, but it seems like added compiler complexity (and code-space inefficiency) for no benefit to the user. Note that it's not easy for the Adjust_Whole_Object_For_Initialization procedure to keep track of which Adjusts were successful -- any subset of them might fail, so it has to keep a bit for each adjustable subcomponent (it's not like initialization, where the first failure is all that has to be recorded). But those might be buried in discriminant-dependent arrays -- it's not clear how many bits are needed, nor where to allocate them. Surely we're not going to require allocating them in the object itself, just for this obscure case! On the other hand, if we're going to relax the principle to make the compiler's life easier, we shouldn't try to keep the hole in the dike small. We should instead say that an exception propagated by Initialize, Finalize, or Adjust is erroneous. Or we could say that it aborts the whole program, although there's no precedent for that kind of rule. Summary: We should say one of: (Big hole) any exception in these procedures is erroneous. (Or some other suitably disastrous consequence, allowing the compiler to relax.) or (No hole) when Adjust fails, all other pending adjusts are done, and then P_E is raised, causing all the successfully adjusted ones to be finalized. In addition, it is implementation dependent whether the unsuccessfully-adjusted ones also get finalized. We should NOT choose: (Small hole): When Adjust fails for one subcomponent, this might cause Finalize for other subcomponents to be skipped. or (No hole, but overly complex): Finalize exactly those for whom Adjust succeeded. > The problem is, if the Adjust_Whole_Object propagates Program_Error, > then we don't register the whole object for finalization. We also > don't register any part of the object for finalization, even > those parts that were successfully adjusted, since we don't have > any record of which parts succeeded versus which parts failed. This seems bad. > The straightforward solution to this problem is to have a separate ^^^^^^^^^^^^^^^ > Adjust_Whole_Object_For_Initialization routine for each tagged > type, which rather than just raising Program_Error when one or more > parts fail to adjust, will also finalize any parts that were successfully > adjusted before raising Program_Error. That seems like a misuse of the term "straightforward", to me. ;-) > Is there some way to have a single Adjust_Whole_Object routine > per tagged type? I've thought of some, but they all seem even *worse*. >... One possibility is to go ahead and register > the whole object for finalization if at least one part succeeds, > and then live with the fact that we are going to finalize parts > whose Adjust failed. That seems like the right solution, to me (assuming we want to stick with the "no infection" principle). >... That could happen as a result of an assignment > statement anyway, and the only thing being corrupted is a part > that was already "hosed" to begin with. Right. > Another possibility is to leave things as we have them now, which > means no part is finalized if any parts fail. The problem with that > is that one messed up controlled abstraction can have the effect > of progressively messing up any other controlled abstraction, just > by both being used as components of the same object. Agreed -- I don't like that solution. > The "finalize-all-if-any-succeeds" therefore seems better to me than > "finalize-none-if-any-fails" approach, but of course neither > matches 7.6.1(4) which says "finalize-only-what-succeeds". Agreed. > In the spirit of AI95-179, the ARG might say that exceptions inside > Adjust or Finalize are bad news anyway, and we should permit some > relaxation of 7.6.1(4) in one direction or the other. > > Alternatively, the ARG says that the independence of controlled abstractions > is quite important, and we should minimize failure coupling between > them even if they appear as components of the same object, and > hence stick with the exact 7.6.1(4) approach. But we can relax 7.6.1(4) in *one* direction without causing failure coupling. - Bob **************************************************************** !section 7.6.1(4) !subject Classwide Adjust and exceptions !reference RM95 7.6.1(4,16) !reference 1997-15759.a !from Bob Duff !reference 1997-15762.a Robert A Duff 1997-7-28>> !discussion > The problem with that is that of course, if Adjust propagates an > exception, later Adjusts won't get done. Thus there is a minor > violation of the rules as written. It seems OK to skip some pending Adjusts, so long as the corresponding Finalizes don't happen. Actually, I wonder if the implementation permissions in 7.6(18-21), as extended by AI95-147 (which is not yet approved), already allow this? The AI says: Matching pairs of Adjust/Finalize and Initialize/Finalize may be eliminated by the implementation. A variable that is never otherwise referenced can be eliminated, even if its Initialize or Finalize has side effects. Since the subcomponent in question will not be further referenced, why can't we eliminate the Adjust/Finalize of it? > In this case, however, that can only be detected by a pathological > program which is counting the number of Adjust calls. (Like, > unfortunately, most validation tests). I believe many of those validation tests are wrong. - Bob **************************************************************** !section 7.6.1(4) !subject Classwide Adjust and exceptions !reference RM95 7.6.1(4,16) !reference Tucker Taft 97-07-25 !from Randy Brukardt 97-07-25 !reference 1997-15760.a Randy Brukardt 1997-7-25>> !discussion >The problem is, if the Adjust_Whole_Object propagates Program_Error, >then we don't register the whole object for finalization. We also >don't register any part of the object for finalization, even >those parts that were successfully adjusted, since we don't have >any record of which parts succeeded versus which parts failed. >This seems to violate the requirement of 7.6.1(4) which says >that any object that is successfully initialized must be finalized. >Is there some way to have a single Adjust_Whole_Object routine >per tagged type? No. I gave up on that quite a while back. However, see below. >One possibility is to go ahead and register >the whole object for finalization if at least one part succeeds, >and then live with the fact that we are going to finalize parts >whose Adjust failed. That could happen as a result of an assignment >statement anyway, and the only thing being corrupted is a part >that was already "hosed" to begin with. >Another possibility is to leave things as we have them now, which >means no part is finalized if any parts fail. The problem with that >is that one messed up controlled abstraction can have the effect >of progressively messing up any other controlled abstraction, just >by both being used as components of the same object. >In the spirit of AI95-179, the ARG might say that exceptions inside >Adjust or Finalize are bad news anyway, and we should permit some >relaxation of 7.6.1(4) in one direction or the other. There is a third approach here, which I think avoids all of the problems, but still works usefully for this case. Our compiler registers each component immediately after it is assigned and adjusted successfully. (Note that regular assignment works very much as Tucker describes it; I'm only talking about initialization assignments or "explicit initializations" here.) The problem with that is that of course, if Adjust propagates an exception, later Adjusts won't get done. Thus there is a minor violation of the rules as written. In this case, however, that can only be detected by a pathological program which is counting the number of Adjust calls. (Like, unfortunately, most validation tests). That's because if initialization propagates an exception, the object is immediately finalized. (In our case, that happens automatically with the regular finalization mechanism.) Therefore, I recommend relaxing the monolithic Adjust for initialization assignments. Sibling components that the monolithic Adjust would handle (but my proposal would not) cannot be accessed anyway (as the object will be immediately destroyed), so they do not do anything useful. Parent components that the monolithic Adjust would handle (but my proposal would not), in addition, would be saved the potential problem of dealing with trashed components with failed Adjusts. Note that the reason for the monolithic Adjust on regular assignments (that the object will be accessible afterwards, so we need to do as many Adjusts as we can) does not apply in the initialization assignment case. Therefore, I propose changing 7.6.1(16) to read: For an Adjust invoked as part of an assignment_statement, any other adjustments due to be performed are performed, and then Program_Error is raised; for an Adjust invoked as part of some other assignment operation, Program_Error is raised. We could also just word this as a permission. "any other adjustments due to be performed may be performed". Randy. **************************************************************** !section 7.6.1(4) !subject Classwide Adjust and exceptions !reference RM95 7.6.1(4,16) !reference 1997-15759.a Tucker Taft !reference 1997-15762.a Bob Duff !from Randy Brukardt !reference 1997-15764.a Randy Brukardt 1997-7-28>> !discussion >> The problem with that is that of course, if Adjust propagates an >> exception, later Adjusts won't get done. Thus there is a minor >> violation of the rules as written. >It seems OK to skip some pending Adjusts, so long as the corresponding >Finalizes don't happen. >Actually, I wonder if the implementation permissions in 7.6(18-21), as >extended by AI95-147 (which is not yet approved), already allow this? >The AI says: > > Matching pairs of Adjust/Finalize and Initialize/Finalize may be > eliminated by the implementation. A variable that is never otherwise > referenced can be eliminated, even if its Initialize or Finalize has > side effects. > >Since the subcomponent in question will not be further referenced, why >can't we eliminate the Adjust/Finalize of it? I think this logic is correct. Therefore, we don't even need a rule change to be allowed to implement this sensibly. Certainly, my approach is a lot easier to implement than the one suggested by Tucker, and it does not contain any hole. (If it did, there is a problem with AI-147). BTW, I have not received any of this discussion via the comment repeater, so I assume it is still not working. Has anyone else?? **************************************************************** !section 7.6.1(4) !subject Classwide Adjust and exceptions !reference RM95 7.6.1(4,16) !reference 1997-15759.a Tucker Taft !reference 1997-15762.a Bob Duff !reference 1997-15764.a Randy Brukardt !from Tucker Taft 97-07-28 !reference 1997-15765.a Tucker Taft 1997-7-28>> !discussion > ... > I think this logic is correct. Therefore, we don't even need a rule change > to be > allowed to implement this sensibly. Certainly, my approach is a lot easier to > implement than the one suggested by Tucker, and it does not contain any hole. > (If it did, there is a problem with AI-147). Your approach, where you raise the exception immediately, only works because you register as you go. This probably isn't what is wanted for the assignment statement, so your approach still requires separate routines per tagged type for Adjust-for-initialize, and Adjust-for-assignment-statement. That's not the end of the world, as far as I am concerned, but if I could use just one that would be simpler for our implementation. (And save the user some code space and compile-time.) If we are allowed to Finalize fields that fail during Adjust, then I could use a single routine that would raise one of two different exceptions, one special one meaning that there was at least one success, and any other meaning that there was no successful Adjust. > BTW, I have not received any of this discussion via the comment repeater, so I > assume it is still not working. Has anyone else?? As I mentioned in a separate note, you should now be receiving comments each midnight. -Tuck **************************************************************** !section 7.6.1(4) !subject Classwide Adjust and exceptions !reference RM95 7.6.1(4,16) !reference 1997-15759.a Tucker Taft !reference 1997-15762.a Bob Duff !reference 1997-15764.a Randy Brukardt !from Bob Duff !reference 1997-15768.a Robert A Duff 1997-7-28>> !discussion > Your approach, where you raise the exception immediately, only works because > you register as you go. This probably isn't what is wanted for the assignment > statement, so your approach still requires separate routines per tagged > type for Adjust-for-initialize, and Adjust-for-assignment-statement. True, but at least the Adjust-for-initialize routine only needs to record a single failure, not an arbitrary set of failures (for various subcomponents of discriminant-dependent arrays and so forth!). Once the failure occurs, it finalizes any previously-adjusted parts, and then gives up. > That's not the end of the world, as far as I am concerned, but if > I could use just one that would be simpler for our implementation. > (And save the user some code space and compile-time.) Agreed -- a single whole-Adjust routine is simpler, and more efficient, than two. > If we are allowed to Finalize fields that fail during Adjust, then > I could use a single routine that would raise one of two different > exceptions, one special one meaning that there was at least one success, > and any other meaning that there was no successful Adjust. I don't understand what you mean, here. I see one exception -- Program_Error -- why do you see two? If P_E_ is raised, the whole-object will get finalized, and if that contains some parts that failed, tough luck (under that "interpretation"). - Bob **************************************************************** !section 7.6.1(4) !subject Classwide Adjust and exceptions !reference RM95 7.6.1(4,16) !reference 1997-15759.a Tucker Taft !reference 1997-15762.a Bob Duff !reference 1997-15764.a Randy Brukardt !reference 1997-15765.a Tucker Taft !from Randy Brukardt 97-07-29 !reference 1997-15772.a Randy Brukardt 1997-7-30>> !discussion >Your approach, where you raise the exception immediately, only works because >you register as you go. This probably isn't what is wanted for the assignment >statement, so your approach still requires separate routines per tagged >type for Adjust-for-initialize, and Adjust-for-assignment-statement. True, but I think it is a red herring. I think you agree that you have to generate separate code for initialize-assignment and assignment-statement. (Aside: We didn't used to do that, using a single thunk, but the Ada 95 rules make that just too messy, so we now generate two thunks.) An Adjust-whole-object routine is necessary in order to provide the proper semantics; that is, to insure that all Adjusts get done if any raise an exception. However, the proposed Adjust/Register pairing does not have this property. It can be in-lined as part of the assignment code, either as part of an init-assign thunk (as we do), or directly in-line. Therefore, this approach does NOT require an additional routine (of course, you're always free to build as many routines as you want. :-). It does take a bit of additional code space, but getting the correct semantics in Ada often does that (over the way you'd do it if you didn't have to follow those silly rules. :-) I doubt it takes as much code as handling Unchecked_Deallocation properly, for example. I cannot support relaxing the rules any further in this area. My other hand is involved in constructing a significant interface (CLAW) which depends heavily on Initialize / Adjust / Finalize semantics. Our experience with the permissions is that it can be very hard to determine what exactly is going to happen (especially in portable code). This is especially true with rules that allow the elimination of Adjusts without corresponding elimination of Finalize (i.e. 7.6.1(21), last sentence). I bet most users of controlled types will be surprised to find that they have to include at least one aliased component before they can trust that common techniques like reference counting will work. (Personally, I thunk users will be happiest if compiler writers ignore that permission - I certainly intend to). From an abstraction viewpoint, it is important that no extra Finalizes be called on my abstraction unless Initialize or Adjust has successfully completed. As the constructor of the abstraction, I know that MY Initialize, Adjust, and Finalize cannot propagate an exception. (Of course, during testing, this assumption gets violated a lot!). The property I want to insure is that the failure of someone else's Initialize or Adjust does not cause my Finalize to either be skipped or called extra times. (Note: Finalize, of course, is constructed to allow calling multiple times. We do that with a flag "Active", which is set to False during a Finalize call. If "Active" is False, Finalize does nothing. However, that does not help for a Adjust which is not called, because the components of the source object were copied in, resetting "Active" flag. Therefore, it is imperative that extra Finalizes not be generated on items which have not be Adjusted. Randy. **************************************************************** From: Robert A Duff[SMTP:bobduff@world.std.com] Sent: Thursday, April 09, 1998 7:20 PM Subject: Re: AI-00193/1 > !standard 07.06.01 (04) 98-04-09 AI95-00193/01 ... > still be finalized when the scope is existed. ^^^^^^^^^^^^^^^^ You misspelt "master is left". ;-) > Hence, in the default initialization case, if the Adjust operation of > the first controlled component fails, the initialization of the second > controlled component can be skipped completely, and only the ^^^^^^ "can be" should be "is", assuming you mean "first" wrt the order of initialization chosen by the impl. Or did you mean wrt textual order of component decls? - Bob **************************************************************** From: Tucker Taft[SMTP:stt@inmet.com] Sent: Friday, April 10, 1998 10:38 AM To: arg95@sw-eng.falls-church.va.us Subject: Re: AI-00193/1 A few new thoughts on the issue of "adjust operations due to be performed": > ... > As a point of clarification, adjustments "due to be performed" > are all those associated with a single assignment operation. > If a composite object is default initialized, and it has > two controlled components each of which has its own > explicit initialization expression, the adjustment of the > second controlled component is not "due to be performed" just because > the first controlled component's adjust operation has been > invoked. By contrast, if such a composite object is initialized > as a whole by assignment, then the adjust operations of all of its > controlled parts are "due to be performed" as soon as the bytes > representing the source (right-hand-side) of the assignment operation > are copied on to the composite object being initialized. > ... I'm not sure I buy this rule any more. There seems no harm in stopping after the first failing Adjust operation in the case of an assignment operation used as part of initialization, so long as only parts for which Adjust has been invoked are in fact finalized. In an assignment statement, the whole object is eventually going to be finalized, so clearly you want to go ahead and do all the Adjusts for parts that have been copied onto, even if one of them fails. For initialization, it seems permissible to conceptuallly do component by component assignment/adjustment, even if the implementation starts by doing a block copy into the uninitialized storage, so long as parts that have not been adjusted are not finalized. So all in all, my attempt to "clarify" what is meant by "adjustments due to be performed" should probably be ignored. There is perhaps something we could say to clarify the intent of "due to be performed," but I am too lazy to figure it out right now. Maybe "do the right thing" ;-). -Tuck **************************************************************** From: Gary Dismukes[SMTP:dismukes@gnat.com] Sent: Friday, April 10, 1998 1:51 PM Subject: Re: AI-00193/1 > I'm not sure I buy this rule any more. There seems no harm in > stopping after the first failing Adjust operation in the case of > an assignment operation used as part of initialization, so long > as only parts for which Adjust has been invoked are in fact finalized. I agree, we shouldn't require all components to be adjusted on init-by-assignment. That seems like overspecification and could have an undesirable impact on some existing implementations. **************************************************************** From: Randy Brukardt[SMTP:Randy@rrsoftware.com] Sent: Friday, April 10, 1998 3:37 PM Subject: RE: AI-00193/1 Tucker: Thanks for noticing that the AI goes too far. That saves me having to figure it out how to explain it. I think it is important that we not force existing implementations to change here (unless they want to, or if they are actually wrong.) This is a failure case, and the important issue is to write the rules so that the failure of one abstraction doesn't kill an unrelated one. We don't want or need to over-specify the behavior beyond that needed to insure that. As noted previously in my mail on the subject (attached to the AI), it is reasonably possible to implement the correct semantics (taking into account AI-147 permissions) without much additional code. While an extra permission which allows even less code to be used is attractive, it certainly should not be made into a requirement --the improvement in code size may not be significant for many applications. **************************************************************** From: Tucker Taft[SMTP:stt@inmet.com] Sent: Friday, April 10, 1998 3:12 PM Subject: Re: AI-00193/1 Gary Dismukes writes: > I agree, we shouldn't require all components to be adjusted on > init-by-assignment. That seems like overspecification and could > have an undesirable impact on some existing implementations. Yes. I think the key requirements are: 1) A part of an object must be finalized if and only if it has been either successfully default initialized, or, as part of initialization-by-assignment, been adjusted (successfully or not). 2) During an assignment statement, once a part of the LHS object is overwritten with a copy of the corresponding part of the right-hand-side, that part must be adjusted. Presuming these requirements are satisfied, I don't see any need for the notion of "adjustments due to be performed" during initialization by assignment. During an assignment *statement*, the "adjustments due to be performed" are defined by requirement (2), namely once some part of the LHS object has been overwritten, adjustment is "due to be performed" on that part of the LHS object. -Tuck ****************************************************************