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-Thread: 103376,a3f460aaba1863e2 X-Google-Attributes: gid103376,public X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news1.google.com!news4.google.com!news.glorb.com!border1.nntp.dca.giganews.com!local01.nntp.dca.giganews.com!nntp.megapath.net!news.megapath.net.POSTED!not-for-mail NNTP-Posting-Date: Wed, 03 Aug 2005 15:00:43 -0500 From: "Randy Brukardt" Newsgroups: comp.lang.ada References: <1120752411.808598.292980@g49g2000cwa.googlegroups.com> <1121269243.013754.57720@g14g2000cwa.googlegroups.com> <1121883276.400592.326630@o13g2000cwo.googlegroups.com> <1122315253.757948.150350@z14g2000cwz.googlegroups.com> <8_ydncLVTeRn5njfRVn-jA@megapath.net> <1122485760.918191.274380@f14g2000cwb.googlegroups.com> <1122545378.984920.272260@g47g2000cwa.googlegroups.com> <1122998146.914353.174110@g44g2000cwa.googlegroups.com> Subject: Re: Private primitive operations available to entire package hierarchy. Can it be done? Date: Wed, 3 Aug 2005 15:03:35 -0500 X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 5.50.4952.2800 X-Mimeole: Produced By Microsoft MimeOLE V5.50.4952.2800 Message-ID: NNTP-Posting-Host: 64.32.209.38 X-Trace: sv3-QYIGG1naFelL3u00qi6fj9l0wqLJs+vDGV24jElnNKr7/a8PTaL+shNhEmbtb22a2/UDrW+FJ6ZLy+L!H+vW5wHyr6SAaj5rQw7+xhQVUImjTnUoA7FTUirKV9AEDG0MLgqIf/r0kalXUpQz91SfYfTiKHfL X-Complaints-To: abuse@megapath.net X-DMCA-Complaints-To: abuse@megapath.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.3.32 Xref: g2news1.google.com comp.lang.ada:3941 Date: 2005-08-03T15:03:35-05:00 List-Id: "Lucretia" wrote in message news:1122998146.914353.174110@g44g2000cwa.googlegroups.com... > > If you use access types in the parameters, then the users of your interface > will have to either: > > * use an allocator (new) to create objects. In that case, they'll have to > use Unchecked_Deallocation to get rid of them. That puts a lot of effort on > the user that they may not need the power of (often stack allocation is just > fine for objects); or > > > Well this can be hidden away inside a "Create" subprogram as per > GtkAda, and as you have to create this kind of "constructor" for Ada > types anyway, I don't see the problem? The problem is storage leakage. You can't (in Ada) put a finalize routine on an access type, so there is no way to reclaim the memory when the object disappears. You'd have to use an explicit Destroy routine, and that puts the burden on the users, and it doesn't work very well, either, because it isn't safe against exceptions propagating, aborts, and the like. Our earliest versions of Claw required such routines, and we found that they were very difficult to use and debug, because any mistake tended to leave dead objects around -- which then raised more exceptions and eventually caused the system to deadlock. > e.g. I currently have a New_Frame which will do any construction > necessary for this type, basically it'll call the C constructor > function which calls "new wxFrame(...)" and returns the pointer back to > Ada which stores it inside wxObject in the wx.Base.Object.Object_Type > as a System.Address. > > If I then derive a new frame type (My_Frame), I should also create a > New_My_Frame primitive which calls New_Frame first on the object, then > do any other construction necessary for My_Frame. Right. I believe that is best done on objects, not on accesses. (Claw uses procedure constructors because copying of objects inherent in Ada 95 functions is problematical.) > > * declare objects with the ugly "aliased" syntax, and worse, have to use the > 'Unchecked_Access attribute in most calls. Which means a lot of extra typing > (and more importantly, reading) that has nothing to do with their program. > > > Well, I have Limited_Controlled as my root tagged type and I still have > to use aliased, so that blatantly doesn't work, unless I'm missing > something. You must be missing something, because its not necessary *in the user code*. I've tried to explain that several times already, and I don't think I can explain it any better than I already have. And I don't want to try to design your interface for you... > > Moreover, if you use access types in this way, you're preventing the users > from using an Ada.Containers container to do their memory management. They'd > have to put access values into the container, and do their own memory > management on those values -- pretty much defeating the purpose of a container. > > > Because the containers have their own access types inside the packages, > right? No, because you can't get an access to the element stored in a container. (Well, that's not *quite* true, you could use 'Address and Address_to_Access_Conversions, but that's certainly not guaranteed to work.) > So, you're saying I should do the following in each of my packages: > > type Some_Type is new Some_Base_Type with private; > type Some_Access is access all Some_Type; > type Some_View is access constant Some_Type; I would not declare access types in the user part of the specification. If the user needs them, they can declare them easily enough, and if you declare them, they can't use a custom storage pool. If *you* need them for the implementation, declare them in the private part. My rule is to never force the user to use access types - give them the maximum flexibility by allowing them to chose the appropriate way to declare the objects of your binding. But if you really need them, they ought to be classwide (I usually use "any" in the name to reflect this): type Any_Some_Access is access all Some_Type'Class; type Any_Some_View is access constant Some_Type'Class; For Ada O-O programming, anything that is not primitive or an object declaration that is specific is suspect. (Sometimes you have to make exceptions for constructors.) > > If you need to use it longer, then you have to make sure that you have > a way to destroy the access value if the object gets finalized while > you are still holding onto the access value. Claw uses controlled types > for this; when an object is finalized, the object > is removed from all lists and other objects that it is in (obviously, > that means making sure that the object keeps track of every place that > it is linked). > > > So, you get hold of the access of every type constructed and keep a > reference counted list of them? Not exactly. In Claw, we have a list of all top-level windows of the application anyway. Child windows are linked to their parents, and vice-versa. So we can traverse all the windows by following that top-level list. When a window *object* is being destroyed, we traverse all of the windows and remove any accesses to the object, whereever they are. We don't reference count, because we're not tracking the accesses, we're tracking the objects. (Remember, you can only manage a collection of objects in Ada, not access values, as you can't have Adjust/Finalize on an access value.) Other types of objects work similarly; typically, they contain a list of all windows that they've been attached to. When one is finalized, it is removed from any windows that it is attached to (which involves not only removing the links, but also issuing any Windows operations needed to remove the objects). We do use something like reference counting to allow Window objects to be assigned. But that capability was a mistake - we wouldn't do it if starting over - so I won't try to describe it. So the main capability (and cost) is that each object has to contain a list of everywhere inside of the binding where it is linked, so it can be removed if the object is finalized (or explicitly destroyed, for that matter). > With the way you have to start the wxWidgets library up, it's more than > fiddly. I've not been able to get reference counting working reliably. > Also getting the app to finalize last is particularly difficult but I > haven't played with it for a while. Termination was a real pain in Claw; for the longest time we used a subprogram that you had to call before exiting. Otherwise the program would deadlock -- and it usually did in practice, because an exception got raised while finalizing something else, or someone aborted a task, or other things. We eventually got it worked out. Randy.