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,FREEMAIL_FROM autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,436e4ce138981b82 X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 2004-03-12 15:02:56 PST Path: archiver1.google.com!news2.google.com!newsfeed2.dallas1.level3.net!news.level3.com!crtntx1-snh1.gtei.net!news.gtei.net!newsfeed1.easynews.com!newsfeed3.easynews.com!easynews.com!easynews!border1.nntp.sjc.giganews.com!nntp.giganews.com!local1.nntp.sjc.giganews.com!nntp.comcast.com!news.comcast.com.POSTED!not-for-mail NNTP-Posting-Date: Fri, 12 Mar 2004 17:02:55 -0600 Date: Fri, 12 Mar 2004 18:02:54 -0500 From: "Robert I. Eachus" User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) X-Accept-Language: en-us, en MIME-Version: 1.0 Newsgroups: comp.lang.ada Subject: Re: abstract sub programs overriding References: <1078776213.376775@master.nyc.kbcfp.com> <1078839257.157439@master.nyc.kbcfp.com> <5cmr40t76va200betf07b7bd6er05ltto9@4ax.com> <1078845298.702789@master.nyc.kbcfp.com> <0ipr40thtf86b520a0qdi003aj87gtuhd4@4ax.com> <1078849973.701176@master.nyc.kbcfp.com> <1078924150.268074@master.nyc.kbcfp.com> <1078934469.744922@master.nyc.kbcfp.com> <1078949096.760629@master.nyc.kbcfp.com> <1079013337.572283@master.nyc.kbcfp.com> In-Reply-To: <1079013337.572283@master.nyc.kbcfp.com> Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Message-ID: <9_mdnfzBlfEC3M_d4p2dnA@comcast.com> NNTP-Posting-Host: 24.147.77.160 X-Trace: sv3-shQ1TAD43LqQ7+v7ISPEUpa3hXvobu7kgiXTp+PMARSvdrQoBlPYPQITn0k95uaodp0Akl+ZqYp+Npn!oIKvJ+rBNsb6D+xyToD3vDmhBhu0PQCD1GqP43aZ180s1x0tt3IF2WZjAweKbA== X-Complaints-To: abuse@comcast.net X-DMCA-Complaints-To: dmca@comcast.net X-Abuse-and-DMCA-Info: Please be sure to forward a copy of ALL headers X-Abuse-and-DMCA-Info: Otherwise we will be unable to process your complaint properly X-Postfilter: 1.1 Xref: archiver1.google.com comp.lang.ada:6295 Date: 2004-03-12T18:02:54-05:00 List-Id: Hyman Rosen wrote: >> procedure Initalize(Object: in out Child) is >> begin >> Do_Something(Object); >> Initialize(Parent(Object)); >> end Initialize; > > Hmm. The understanding in C++ is that in a constructor, all of the base > constructors have completed, so all facilities of the base classes are > available to be used in the derived class constructors. I'm not saying > that this first idiom you describe is wrong for Ada, but it does seem to > force derived classes into having very intimate knowledge of the needs > of their bases. What if initializing the child fields requires making > calls to base methods? Actually this version is used when the extension doesn't need to know anything about the elements (and operations) of the parent, if you need to access the parent fields you need to use the second option: > >> procedure Initialize(Object: in out Child) is >> begin >> Object := (Parent_Type with ...); >> Do_Something_Else(Object); >> end Initialize; > > Nice. In C++ it is highly discouraged to implement constructors via > assignment (because it is fragile and error-prone). If I'm not mistaken, > this code will cause Finalize to be called on Object before the assignment > takes place, which means that it's possible for Finalize to be called on > an object before any Initialize for it has completed. No. Finalize MAY be called on the Parent_Type part of the value being generated (but after the copy into the real Object). If the Parent_Type is Limited_Controlled, then the value should be built in place, and no finalization will occur. The other case where you will get a Finalize before Object has been completely Initialized, if some part of one of the Initialize calls raises an unhandled exception. > I really have to stop > thinking of Initialize/Adjust/Finalize as being equivalent to C++'s > constructor/assignment/destructor. It may just be that I haven't gotten my > mind around it properly, but it seems to me that Ada OO is significantly > harder to understand and explain than Java's or C++'s, even (or especially) > for simple cases. Very much agree. The Ada model is much more complex, since there was a lot of effort put into allowing nesting of controlled objects. For the normal user, though, the real trick is that you may have no user defined Initialize procedure. You give the components of the controlled object default initial values and you are done. A better way to explain it is to point out that during development, the focus was on finalization. The initialization in Ada 83 was sufficient for most users. So for 99% of tagged types, there are no user defined Initialize procedures--and it works just fine. Adjust is typically only used to provide deep copy semantics. >> So yes, there are areas where user written code can access an object >> that has not yet been completely initialized. But in practice, as a >> user you will find that once you get rid of any bugs (and exceptions) >> inside Intialize, Adjust, and Finalize, that code written by others, >> including the authors of types derived from your types, cannot mess up >> the invariants of your type. > > I agree. But that's why I said that DK was wrong. Our discussion has been > about code that runs during object construction and destruction. That is, > the process of getting rid of the bugs and exceptions that you mention. And what DK and I have been saying is that there is no problem, because of the "two stage" initialization of Ada tagged types. Compilers can shortcut the process of building an object, if the compiler can prove that it makes no difference. But other reading such an object in the debugger, the only way to get an uninitialized or abnormal subcomponent in a tagged object is to do something in that corrupts the subcomponent, then handle the exception and throw it away. (And as I keep saying, if you throw the execption away without fixing the problem, you are definitely in "here be dragons" territory. But that is true no matter where you do that.) > That's not what I was talking about. I was saying that in a parent > Initialize, the object could be view-converted to its classwide type, > and then a dispatching call to could be made on the converted object > which would wind up calling an overridden method of the child's type. How many times do I have to say it. You can try to DO that, but writing working code that does that is very hard--not impossible. But if and when you get that code to compile, surprise! the object is initialized correctly. The problem, or more appropriately what prevents the problem, is the order of elaboration rules in Ada. To get the problem case, you need to create an object of the child type before the body of the parent package is elaborated. So you need not only for the body of the package that declares the parent type to reference the child type, you need to create an object of the parent type before the main program is elaborated. There will be cases where, if you try to do this, there would be a possible elaboration order which the Ada rules don't allow. (Mix the elaboration of procedures from the two package bodies.) You can use nested calls and additional procedures in a third unit to make it all work. But as I said then it all works. So "down casting" to a child type in the body of the package which declares the parent is not illegal as such. But if they are controlled, and you have different explicit Intialize procedures for the two types, and you create objects before the main program executes, it is VERY hard to get the resulting code to link. > Think of the template-method design pattern for example. (This would > be in your idiom one code, but with the parent's Initialize called > *before* the Do_Something(Object), because Do_Something requires that > its base classes be completely set up.) So overridden methods could > wind up being called on incompletely prepared objects. This can't > happen in C++. There, the dispatching would only go to methods of the > class whose constructor or destructor is running. If such a method is > abstract, the implementation generally arranges for the program to > abort. Again, it is very easy and natural in most cases. Even if you have two explicit Initialize procedures, which in Ada is rare, the only problem is if, as above, Initialize for the parent requires the body of the child type to be elaborated, and there are objects of the type created before the main program starts executing. Doing all of this is very bad form. Doing one or two of the three is not a problem. But it is usually referencing the body of the child package from the body of the parent package that Ada programmers avoid. In Ada, elaboration order issues are an emergent property of a program as a whole. There are a few rules though that you can follow to avoid ever having elaboration order (or compile order problems) this is one of them. If for some reason you have to break it, do so. But it will usually be painful to get right. -- Robert I. Eachus "The only thing necessary for the triumph of evil is for good men to do nothing." --Edmund Burke