* Destructor question @ 1998-12-02 0:00 Rusnak 1998-12-03 0:00 ` Jeff Carter ` (2 more replies) 0 siblings, 3 replies; 12+ messages in thread From: Rusnak @ 1998-12-02 0:00 UTC (permalink / raw) How are destrcutor methords properly implemented in Ada on tagged records? I have the following setup: Given a tagged record type: type Instance is abstract tagged record ... end record; type Object is access all Instance; type Class_Object is access all Instance'Class; and a package which keeps a container of "Class_Object"s. At the end of the day, I need to deallocate all the objects in the container. The only way I could envision doing this is to write a Dispose procedure which takes an access to an instance and dispatches to the approriate package (the one where the corresponding subclass of Instance is actually defined) to do the deallocation. The Dispose procedure would dispose of the internals of the object (if necessary) and then dispose of the object itself. The procedure therefore needs to take an "in out Object" type: procedure Dispose(The_Object: in out Object) is abstract; I can't dispatch on this procedure, however, since it explicitly takes an Object type and passing in a Class_Object type causes a compilation error. I can'e use an anonymous access type, since these are only "in" parameters, and the access value of The_Object should be set to null after deallocation. Any suggestions are greatly appreciated. My e-mail id is "jrusnak "on the domain "netgate.net". Thanks -John ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Destructor question 1998-12-02 0:00 Destructor question Rusnak @ 1998-12-03 0:00 ` Jeff Carter 1998-12-03 0:00 ` Rusnak 1998-12-06 0:00 ` david.c.hoos.sr 1998-12-06 0:00 ` Matthew Heaney 2 siblings, 1 reply; 12+ messages in thread From: Jeff Carter @ 1998-12-03 0:00 UTC (permalink / raw) Rusnak wrote: > > How are destrcutor methords properly implemented in Ada on tagged > records? I have the following setup: > ... Assuming "destrcutor" should be "destructor" and "methords" should be "methods" then the answer to this question is that Ada does not have methods, much less destructor methods. Ada has subprograms and entries. This is a MicroStuff Support answer: technically correct but useless. Here's a useful answer: Your question seems to be about what Ada calls "finalization", which refers to operations on objects of a type when the value of the object becomes inaccessible (prior to assignment or when the object ceases to exist). I refer you to the standard package Ada.Finalization for the details of finalization in Ada (ARM 7.6). -- Jeff Carter E-mail: carter commercial-at innocon [period | full stop] com "Perfidious English mouse-dropping hoarders." Monty Python & the Holy Grail ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Destructor question 1998-12-03 0:00 ` Jeff Carter @ 1998-12-03 0:00 ` Rusnak 1998-12-04 0:00 ` Robert I. Eachus ` (2 more replies) 0 siblings, 3 replies; 12+ messages in thread From: Rusnak @ 1998-12-03 0:00 UTC (permalink / raw) Jeff Carter wrote: > Rusnak wrote: > > > > How are destrcutor methords properly implemented in Ada on tagged > > records? I have the following setup: > > ... > > Assuming > > "destrcutor" should be "destructor" > > and > > "methords" should be "methods" > > then the answer to this question is that Ada does not have methods, much > less destructor methods. Ada has subprograms and entries. > > This is a MicroStuff Support answer: technically correct but useless. > Here's a useful answer: > > Your question seems to be about what Ada calls "finalization", which > refers to operations on objects of a type when the value of the object > becomes inaccessible (prior to assignment or when the object ceases to > exist). I refer you to the standard package Ada.Finalization for the > details of finalization in Ada (ARM 7.6). > > -- > Jeff Carter > E-mail: carter commercial-at innocon [period | full stop] com > "Perfidious English mouse-dropping hoarders." > Monty Python & the Holy Grail Sorry about the spelling mistakes on earlier post. The key terms "method" and "attribute" are object-oriented terms (which I believe are now accepted as part of UML but I can be wrong about that) and are not associated with any particular language. I would agree that Ada class objects do not have a "this" pointer, but tagged records do support dispatching operations which are essentially "methods" of the class. Now to the more important question: I assume that IF I am going to use the Ada.Finalization package, that all my tagged records should be based off of the Controlled type within that package. I would may also have to override the Finalize procedure since a derived class could allocate memorey for new attributes of the tagged record. The Finalize, Initialize, and Ajust procedures do NOT take an access type however. What I have is an array of access values to a "'Class" type, and I need to deallocate the memory associated with each of the access values. One cannot write an Unchecked_Deallocation for a "'Class" object (this makes sense). What I need is to write is a dispaching procedure (i.e. a mehotd of a class) like the following: Given a type Instance which is an abstract tagged record and a type Object which is of type access all Instance and a type Class_Object which is of type access all Instance'Class, I would like to define a procedure: procedure Deallocate(The_Object : in out Object) is abstract; which is dispatching. The compiler certainly lets me declare such a procedure, but I can never use it, since it cannot accept a parameter of type Class_Object to get it to dispatch. Another solution is possible, but the above solution (if "implementable") would be the cleanest and least intriusive way to go. On another note, if i override a proceudre in a derived class, how can I "chain" it to its super class (i.e., call within the procedure the super class procedure which it overrides)? I could certainly see the use in chaining the Initialize procedure of the Controlled class mentioned above. Explicit casting doesn't seem to work, and casting is not a very desirable solution anyway. -John ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Destructor question 1998-12-03 0:00 ` Rusnak @ 1998-12-04 0:00 ` Robert I. Eachus 1998-12-06 0:00 ` Matthew Heaney 1998-12-06 0:00 ` Matthew Heaney 1998-12-07 0:00 ` Jeff Carter 2 siblings, 1 reply; 12+ messages in thread From: Robert I. Eachus @ 1998-12-04 0:00 UTC (permalink / raw) In article <3666F7F1.9B107D38@nowhere.com> Rusnak <bogus@nowhere.com> writes: > Given a type Instance which is an abstract tagged record and a type > Object which is of type access all Instance and a type Class_Object which > is of type access all Instance'Class, > I would like to define a procedure: > procedure Deallocate(The_Object : in out Object) is abstract; > which is dispatching. The compiler certainly lets me declare such a > procedure, but I can never use it, since it cannot accept a parameter of > type Class_Object to get it to dispatch. Another solution is possible, but > the above solution (if "implementable") would be the cleanest and least > intriusive way to go. Did you get my e-mail note on this? Anyway what you have do to is to have an operation for the "root" type that takes the access type as a parameter: procedure Deallocate(The_Access : in out Object_Class); Next, you need, and this need not be visible, to have a two parameter version that is dispatching on Object: procedure Deallocate(The_Access : in out Object_Class; The_Object : in Object); The bodies are fairly straightforward: procedure Deallocate(The_Access : in out Object_Class) is begin Deallocate(The_Access, The_Access.all); end Deallocate; -- This dispatches on the second operand. procedure Deallocate(The_Access : in out Object_Class; The_Object : in Object) is function Free is new Unchecked_Deallocation(Object, Object_Class); begin Deallocate(The_Access.all); -- you may not need this if using Controlled Free(The_Access); end Deallocate; -- There is a LOT of magic going on here. Since this procedure is a -- primitive operation of type Object, it will be derived when you -- create subclasses of Object. Note that the parameter -- "The_Object" is never used, it is just there to get the -- dispatching. The instance(s) of Unchecked_Deallocation are not -- class-wide, so they work. The call to Deallocate is not -- dispatching, but that's all right, the dispatching has already -- been done. The only use of 'Class is in the declaration of -- Object_Class, but that is fine, the call to the two parameter -- Deallocate from the one parameter version dispatches because -- the type of The_Access.all is class-wide. -- Finally, you only need to declare the non-class-wide single -- parameter version of Deallocate, if you are not using Finalize. > On another note, if i override a proceudre in a derived class, how can I > "chain" it to its super class (i.e., call within the procedure the super > class procedure which it overrides)? I could certainly see the use in > chaining the Initialize procedure of the Controlled class mentioned > above. Explicit casting doesn't seem to work, and casting is not a very > desirable solution anyway. Why doesn't explicit casting seem to work? Read about "view conversions" to see that type conversions can do exactly what you want. But in general you shouldn't need to do such "casting" to call the operation on the parent type. Just make the type extensions Controlled instead of (or in addition to) the entire class when you need to do something then call the Adjust, Initialize, or Finalize for the parent. -- Robert I. Eachus with Standard_Disclaimer; use Standard_Disclaimer; function Message (Text: in Clever_Ideas) return Better_Ideas is... ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Destructor question 1998-12-04 0:00 ` Robert I. Eachus @ 1998-12-06 0:00 ` Matthew Heaney 1998-12-08 0:00 ` Robert I. Eachus 0 siblings, 1 reply; 12+ messages in thread From: Matthew Heaney @ 1998-12-06 0:00 UTC (permalink / raw) eachus@spectre.mitre.org (Robert I. Eachus) writes: > Did you get my e-mail note on this? Anyway what you have do to > is to have an operation for the "root" type that takes the access type > as a parameter: > > procedure Deallocate(The_Access : in out Object_Class); > > Next, you need, and this need not be visible, to have a two > parameter version that is dispatching on Object: > > procedure Deallocate(The_Access : in out Object_Class; > The_Object : in Object); An alternative implementation uses a (private) subprogram that takes an access parameter: procedure Do_Deallocate (The_Object : access Object); This of course dispatches on the tag of The_Object. It more-or-less combines the two parameters of Bob's solution into one parameter. > > The bodies are fairly straightforward: > > > procedure Deallocate(The_Access : in out Object_Class) is > begin Deallocate(The_Access, The_Access.all); end Deallocate; > -- This dispatches on the second operand. > > procedure Deallocate(The_Access : in out Object_Class; > The_Object : in Object) is > function Free is new Unchecked_Deallocation(Object, Object_Class); > begin > Deallocate(The_Access.all); -- may not need this if using Controlled > Free(The_Access); > end Deallocate; The bodies of the alternative implementation are: procedure Deallocate (The_Access : in out Object_Class) is begin if The_Access /= null then Do_Deallocate (The_Access); The_Access := null; end if; end Deallocate; procedure Do_Deallocate (The_Object : access Object) is OA : Object_Access := Object_Access (The_Object); begin Free (OA); end; where type Object_Access is an access type that designates the specific type Object. Analogous implementations would be required for each type in the hierarchy. (I prefer to instantiate Unchecked_Deallocation using a specific type, rather than a class-wide one.) A complete example using this technique may be found at the patterns archive at the ACM: <http://www.acm.org/archives/patterns.html> Look under month Nov 1998, and the post labeled "No subject." It discusses an implementation of the Visitor pattern that uses the memory management technique described above. From the original post (not from Bob Eachus): > > On another note, if i override a proceudre in a derived class, how can I > > "chain" it to its super class (i.e., call within the procedure the super > > class procedure which it overrides)? I could certainly see the use in > > chaining the Initialize procedure of the Controlled class mentioned > > above. Explicit casting doesn't seem to work, and casting is not a very > > desirable solution anyway. Sometimes you need to cast. Downcasts from a class-wide type to a specific one are safe. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Destructor question 1998-12-06 0:00 ` Matthew Heaney @ 1998-12-08 0:00 ` Robert I. Eachus 0 siblings, 0 replies; 12+ messages in thread From: Robert I. Eachus @ 1998-12-08 0:00 UTC (permalink / raw) In article <m3k90559po.fsf@mheaney.ni.net> Matthew Heaney <matthew_heaney@acm.org> writes: > An alternative implementation uses a (private) subprogram that takes an > access parameter: > procedure Do_Deallocate (The_Object : access Object); > This of course dispatches on the tag of The_Object. It more-or-less > combines the two parameters of Bob's solution into one parameter. This is essentially a style issue, but for didactic purposes, I wanted to avoid the clash between access parameters and Unchecked_Deallocation. Matt's example deals with this correctly, but it is probably more difficult for someone learning Ada to understand. > I prefer to instantiate Unchecked_Deallocation using a specific > type, rather than a class-wide one. I understand, I think, what Matt meant to say here from context, but it is tough to put in correct words. "I prefer to instantiate Unchecked_Deallocation where neither the object type nor the designated type in the formal access parameter is classwide," may be more correct, but it is certainly much harder on the eyes. The difference between Matt's implementation and mine here is in the type designated by the access type, and I just chose to use the one in the original example. However, I strongly agree that you do not want to instantiate Unchecked_Deallocation with a classwide object type. Language lawyers can argue about when this is required to work by the RM but allowed just to not collect the storage (or just do a lot of otherwise unnecessary checking) and when it is allowed to erroneusly collect the wrong amount of storage, but you are much better off not putting the gun to the implementors head. (The problem is that if you instantiate using a classwide type, the compiler won't know when the sizes of the objects of a given subtype are static, and when thunks or some other dynamic method is necessary to determine the amount of space to free. So a "correct" implementation will potentially require creating thunks for all possible target subtypes. If you instantiate for a specific type, even if it is inside a dispatching operation, then the compiler can generate decent code for each instance. Of course, the implementation of the standard storage pool may include a size in each object, but that doesn't help with user defined pools.) -- Robert I. Eachus with Standard_Disclaimer; use Standard_Disclaimer; function Message (Text: in Clever_Ideas) return Better_Ideas is... ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Destructor question 1998-12-03 0:00 ` Rusnak 1998-12-04 0:00 ` Robert I. Eachus @ 1998-12-06 0:00 ` Matthew Heaney 1998-12-07 0:00 ` Jeff Carter 2 siblings, 0 replies; 12+ messages in thread From: Matthew Heaney @ 1998-12-06 0:00 UTC (permalink / raw) I give an example of how to implement a dispatching constructor in my Nov 1998 post (with the subject "No subject", unfortunately) to the ACM patterns archive. <http://www.acm.org/archives/patterns.html> The post itself is titled Yet Another Visitor, and shows how to implement a tagged type with a private operation ("method") that dispatches on the tag of the item, and frees the storage associated with that object. The type Composite_Equipment is very much like your container type: it's a container that contains class-wide objects. If you have trouble locating the post in the archive, send me your real email address and I'll send it to you. Matt Rusnak <bogus@nowhere.com> writes: > Now to the more important question: I assume that IF I am going to use the > Ada.Finalization package, that all my tagged records should be based off of > the Controlled type within that package. I would may also have to override > the Finalize procedure since a derived class could allocate memorey for new > attributes of the tagged record. The Finalize, Initialize, and Ajust > procedures do NOT take an access type however. What I have is an array of > access values to a "'Class" type, and I need to deallocate the memory > associated with each of the access values. One cannot write an > Unchecked_Deallocation for a "'Class" object (this makes sense). What I > need is to write is a dispaching procedure (i.e. a mehotd of a class) like > the following: > > Given a type Instance which is an abstract tagged record and a type > Object which is of type access all Instance and a type Class_Object which > is of type access all Instance'Class, > I would like to define a procedure: > > procedure Deallocate(The_Object : in out Object) is abstract; > > which is dispatching. The compiler certainly lets me declare such a > procedure, but I can never use it, since it cannot accept a parameter of > type Class_Object to get it to dispatch. Another solution is possible, but > the above solution (if "implementable") would be the cleanest and least > intriusive way to go. > > On another note, if i override a proceudre in a derived class, how can I > "chain" it to its super class (i.e., call within the procedure the super > class procedure which it overrides)? I could certainly see the use in > chaining the Initialize procedure of the Controlled class mentioned > above. Explicit casting doesn't seem to work, and casting is not a very > desirable solution anyway. > > -John ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Destructor question 1998-12-03 0:00 ` Rusnak 1998-12-04 0:00 ` Robert I. Eachus 1998-12-06 0:00 ` Matthew Heaney @ 1998-12-07 0:00 ` Jeff Carter 2 siblings, 0 replies; 12+ messages in thread From: Jeff Carter @ 1998-12-07 0:00 UTC (permalink / raw) Rusnak wrote: > ... > Sorry about the spelling mistakes on earlier post. The key terms > "method" and "attribute" are object-oriented terms (which I believe are now > accepted as part of UML but I can be wrong about that) and are not > associated with any particular language. I would agree that Ada class > objects do not have a "this" pointer, but tagged records do support > dispatching operations which are essentially "methods" of the class. We all make typos, but when we make assumptions about another's typos, we should make them clear, in case those assumptions are wrong. There are many who feel a need for new names for concepts that have been well defined for 30 years under other names, but Ada (ISO/IEC 8652:1995) is not among them, nor am I. I call a type a type and a subprogram a subprogram. More to the point, when discussing Ada, it is helpful to use Ada terms. > > Now to the more important question: I assume that IF I am going to use the > Ada.Finalization package, that all my tagged records should be based off of > the Controlled type within that package. I would may also have to override > the Finalize procedure since a derived class could allocate memorey for new > attributes of the tagged record. The Finalize, Initialize, and Ajust > procedures do NOT take an access type however. What I have is an array of > access values to a "'Class" type, and I need to deallocate the memory > associated with each of the access values. One cannot write an > Unchecked_Deallocation for a "'Class" object (this makes sense). What I This compiles fine (GNAT 3.10p1/Win95): with Ada.Finalization; use Ada; package Class_Test is type T is abstract tagged private; type T_Ptr is private; private -- Class_Test type T is abstract tagged null record; type T_Access is access all T'Class; type T_Ptr is new Finalization.Controlled with record Ptr : T_Access; end record; procedure Finalize (Object : in out T_Ptr); end Class_Test; with Ada.Unchecked_Deallocation; use Ada; package body Class_Test is procedure Finalize (Object : in out T_Ptr) is procedure Free is new Unchecked_Deallocation (Object => T'Class, Name => T_Access); begin -- Finalize Free (Object.Ptr); end Finalize; end Class_Test; so possibly you can do what you want directly. You would need some operations to obtain and manipulate values of type T_Ptr (these operations might dispatch). You could then declare and operate on an array of T_Ptr components; when an array object goes out of scope, its components would be deallocated by finalization. Note that Ada's design goals include supporting the creation of readable, easily understood code. The use of type extension and dispatching results in code that is less readable and more difficult to understand than code with the same functionality implemented using composition. Since anything implemented with type extension and dispatching can be implemented using composition, the only reason to use type extension and dispatching is to obtain finalization. -- Jeff Carter E-mail: carter commercial-at innocon [period | full stop] com "Your mother was a hamster and your father smelt of elderberries." Monty Python & the Holy Grail ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Destructor question 1998-12-02 0:00 Destructor question Rusnak 1998-12-03 0:00 ` Jeff Carter @ 1998-12-06 0:00 ` david.c.hoos.sr 1998-12-06 0:00 ` Matthew Heaney 1998-12-08 0:00 ` Robert I. Eachus 1998-12-06 0:00 ` Matthew Heaney 2 siblings, 2 replies; 12+ messages in thread From: david.c.hoos.sr @ 1998-12-06 0:00 UTC (permalink / raw) In article <3665B85D.A2663591@nowhere.com>, Rusnak <bogus@nowhere.com> wrote: > How are destrcutor methords properly implemented in Ada on tagged > records? I have the following setup: <snip> Here is my solution to the problem, based on Robert Eachus's post to this thread. I do, however, find some points of Robert's posting at variance with what I was able to make work, viz.: 1. Robert said "Next, you need, and this need not be visible, to have a two parameter version that is dispatching on Object" I do not see how this can be made invisible, since it needs to be a primitive operation of the type. Perhaps someone can enlightne me on this. 2. Robert said "Note that the parameter "The_Object" is never used, it is just there to get the dispatching." This would be true if it were not for your requirement that you be able to deallocate internal dynamically-allocated components. At any rate, here is a sample program which is a complete and working implementation of Robert's ideas. I hope it helps. The exercise certainly clarified the solution for me. David C. Hoos, Sr. with Ada.Tags; with Ada.Text_Io; with Ada.Unchecked_Deallocation; procedure Test_Rusnak is package Rusnak is type Instance is abstract tagged null record; type Object_Class is access all Instance'Class; -- This procedure can never be called, since no instance of an -- abstract type can exist, but it must exist, otherwise the -- single-parameter Deallocate will not compile. procedure Deallocate (The_Access : in out Object_Class; The_Object : in out Instance); -- This is the class-wide deallocation procedure which is called to -- deallocate any objet of a type derived from Instance. It makes a -- dispatching call to the appropriate two-parameter Deallocate -- procedure which must be a primitive operation for all types derived -- from Instance. procedure Deallocate (The_Access : in out Object_Class); -- This is the type of a component of type Derived. type String_Access is access all String; -- This type is an example of a concrete type derived from Instance -- which has internal dynamically-allocated objects which need to be -- deallocated when an object of the type is deallocated. type Derived is new Instance with record Data_Access: String_Access; end record; -- This is the two-parameter Deallocate procedure, a primitive operation -- of type Derived. It must be declared at this point -- i.e. before -- Derived is frozen. procedure Deallocate (The_Access : in out Object_Class; The_Object : in out Derived); end Rusnak; package body Rusnak is procedure Deallocate (The_Access : in out Object_Class; The_Object : in out instance) is begin null; end Deallocate; -- This type serves only to provide the required parameter type for an -- instantiation of Ada.Unchecked_Deallocation. It must be decalred -- here instead of inside the Deallocate procedure, in order that it -- have the same access level as the type which it accesses. type Derived_Class is access all Derived; -- This procedure is declared outside the Deallocate procedure from which -- it is called, only because it is for a type which would likely be used -- for components of more than one type derived from Instance. procedure Free is new Ada.Unchecked_Deallocation (Object => string, Name => String_access); procedure Deallocate (The_Access : in out Object_Class; The_Object : in out Derived) is procedure Free is new Ada.Unchecked_Deallocation (Object => derived, Name => derived_Class); begin Ada.Text_Io.Put_Line ("Deallocating ""derived"" object"); Free (The_Object.Data_Access); Free (Derived_Class (The_Access)); end Deallocate; procedure Deallocate (The_Access : in out Object_Class) is begin Ada.Text_Io.Put_Line ("Dispatching to deallocator for concrete type """ & Ada.Tags.External_Tag (The_Access.all'Tag) & """."); Deallocate (The_Access => The_Access, The_Object => The_Access.all); end Deallocate; end Rusnak; The_Derived_Object_access : Rusnak.Object_class := new Rusnak.Derived'(Data_Access => new String'("this is the data")); begin Ada.Text_Io.Put_Line (Rusnak.Derived (The_Derived_Object_Access.all).Data_Access.all); Rusnak.Deallocate (The_Derived_Object_Access); Ada.Text_Io.Put_Line("The next statement will raise Constraint_Error"); Ada.Text_Io.Put_Line (Rusnak.Derived (The_Derived_Object_Access.all).Data_Access.all); end Test_Rusnak; -----------== Posted via Deja News, The Discussion Network ==---------- http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Destructor question 1998-12-06 0:00 ` david.c.hoos.sr @ 1998-12-06 0:00 ` Matthew Heaney 1998-12-08 0:00 ` Robert I. Eachus 1 sibling, 0 replies; 12+ messages in thread From: Matthew Heaney @ 1998-12-06 0:00 UTC (permalink / raw) david.c.hoos.sr@ada95.com writes: > Here is my solution to the problem, based on Robert Eachus's post to > this thread. > > I do, however, find some points of Robert's posting at variance with > what I was able to make work, viz.: > > 1. Robert said "Next, you need, and this need not be visible, to > have a two parameter version that is dispatching on Object" I do > not see how this can be made invisible, since it needs to be a > primitive operation of the type. Perhaps someone can enlightne me > on this. Primitive operations aren't necessarily declared in the public region of the spec. For example, in my post about the Visitor pattern, the free operation is primitive, yet private: package Equipment is pragma Pure; type Root_Equipment (<>) is abstract tagged limited private; private type Root_Equipment is abstract tagged limited null record; procedure Do_Free (Equipment : access Root_Equipment); end Equipment; Because operation Do_Free is declared in the private region, is only available within the subsystem of packages rooted at Equipment. Typically, such operations are named Do_<something>, and are used to implement public operations (primitive and class-wide). In the visitor example, Composite_Equipment (an abstract type) implements Do_Free by calling Do_Free on each of its items, which dispatches according to the tag of the item. Thus, Do_Free is a dispatching deconstructor: procedure Do_Free (Composite : access Composite_Equipment) is procedure Free_Item (Item : access Root_Equipment'Class) is begin Do_Free (Item); <-- !!! dispatching deconstructor end; procedure Free_Items is new For_Every_Item (Free_Item); begin Free_Items (Composite); end Do_Free; Cabinet, a non-abstract type which derives from Composite_Equipment, calls its parent's Do_Free (to actually delete the items), then deletes itself: procedure Free (Cabinet : in out Cabinet_Access) is begin if Cabinet = null then return; end if; Do_Free (Composite_Equipment (Cabinet.all)'Access); Deallocate (Cabinet); end Free; Free is the public operation that does deletion. It is implemented by calling Do_Free. Note that this technique is slightly different from the solution suggested by Bob Eachus. The complete post (with compilable code) is located in the Nov 1998 link at the ACM patterns list archive. <http://www.acm.org/archives/patterns.html> ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Destructor question 1998-12-06 0:00 ` david.c.hoos.sr 1998-12-06 0:00 ` Matthew Heaney @ 1998-12-08 0:00 ` Robert I. Eachus 1 sibling, 0 replies; 12+ messages in thread From: Robert I. Eachus @ 1998-12-08 0:00 UTC (permalink / raw) In article <74d0i5$itj$1@nnrp1.dejanews.com> david.c.hoos.sr@ada95.com writes: > 1. Robert said "Next, you need, and this need not be visible, to have a > two parameter version that is dispatching on Object" I do not see how > this can be made invisible, since it needs to be a primitive operation > of the type. Perhaps someone can enlightne me on this. Matt Heane answered this--dispatching operations can be declared in the private part if they are not part of the exported interface. But they still have to be declared before the type is frozen (see 3.9.2(13)), and there are certain other limitations. (See 3.9.3(10).) > 2. Robert said "Note that the parameter "The_Object" is never used, it is > just there to get the dispatching." This would be true if it were not > for your requirement that you be able to deallocate internal > dynamically-allocated components. It can be used, but I recommend against it. In my example, I only used the access parameter, but if you need to do anything to the object, I strongly recommend using ".all" applied to the access parameter. If someone writes a call where the object type is wrong, you will get an error at run-time. But if the object is of the correct type but not the target of the access parameter, you will have a very hard to find bug. It is possible to put an explict check in, but it is much easier just to avoid using the value of the parameter, or as Matt suggested, use a single access parameter. (But then you have to make a copy to pass to Unchecked_Deallocation, then explicitly set the outer parameter to null.) -- Robert I. Eachus with Standard_Disclaimer; use Standard_Disclaimer; function Message (Text: in Clever_Ideas) return Better_Ideas is... ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Destructor question 1998-12-02 0:00 Destructor question Rusnak 1998-12-03 0:00 ` Jeff Carter 1998-12-06 0:00 ` david.c.hoos.sr @ 1998-12-06 0:00 ` Matthew Heaney 2 siblings, 0 replies; 12+ messages in thread From: Matthew Heaney @ 1998-12-06 0:00 UTC (permalink / raw) Rusnak <bogus@nowhere.com> writes: > How are destrcutor methords properly implemented in Ada on tagged > records? I have the following setup: > > Given a tagged record type: > > type Instance is abstract tagged > record > ... > end record; > > type Object is access all Instance; > > type Class_Object is access all Instance'Class; > > and a package which keeps a container of "Class_Object"s. > > At the end of the day, I need to deallocate all the objects in the > container. Hers's an idea: generic type Item_Type is tagged private; package Containers is type Container_Type is limited private; procedure Add (Item : in Item_Type'Class; To : in out Container_Type); ... private type Item_List is <list of pointers to Item_Type'Class>; type Container_Type is new Ada.Finalization.Controlled with record Items : Item_List; end record; procedure Finalize (Container : in out Container_Type); end Containers; package body Containers is procedure Finalize (Container : in out Container_Type) is begin <remove all items in Container.Items> end; ... end Containers; ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~1998-12-08 0:00 UTC | newest] Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 1998-12-02 0:00 Destructor question Rusnak 1998-12-03 0:00 ` Jeff Carter 1998-12-03 0:00 ` Rusnak 1998-12-04 0:00 ` Robert I. Eachus 1998-12-06 0:00 ` Matthew Heaney 1998-12-08 0:00 ` Robert I. Eachus 1998-12-06 0:00 ` Matthew Heaney 1998-12-07 0:00 ` Jeff Carter 1998-12-06 0:00 ` david.c.hoos.sr 1998-12-06 0:00 ` Matthew Heaney 1998-12-08 0:00 ` Robert I. Eachus 1998-12-06 0:00 ` Matthew Heaney
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox