Excuse me if you receive this mail twice, but I got an error message from the
Webmaster, so I repost it.
Robert I. Eachus ([log in to unmask]) wrote:
>Heath White ([log in to unmask]) said:
>> One of the main headaches this causes occurs when you already have
>> a tagged hierarchy of types. You want to derive off from it, but
>> you want the new type to have controlled behavior. There is no
>> good way to do this.
> Of course there is, but in part it is non-intuitive ...
> If you are adding a component that needs to be controlled, the
> controlledness is a property of the component, and the language
> supports that correctly. It has to, since you might not be aware
> that the component you are adding to a non-controlled class is
> The more "troubling" case is when the addition of a component
> creates a need to finalize the containing structure. Access
> discriminants allow the component to see the containing structure.
> I keep meaning to create an abstraction which deals with the most
> common sort of such extensions separate from other "building block"
> tagged components. It is less than twenty lines long -- but
> choosing some of those lines correctly takes thought. Hmmm...
> This version has the side effect of making the extended type
> limited. The body for a non-limited version is much more complex
> because you have to use a record with an access value as a non-
> discriminant, then track assignment and copying using Initialize
> and Adjust. (Left as an exercise for the reader.)
> There is however one "can't be avoided" problem. The order in which
> the finalization of two extensions will be called is determined in
> part by the subclassing order (see RM 7.6.1(9)) and in part by
> whether or not there is an access discriminant. If you have too
> many components trying to finalize things, the ordering can get to
> be a problem.
> Robert I. Eachus
> with Standard_Disclaimer;
> use Standard_Disclaimer;
> function Message (Text: in Clever_Ideas) return Better_Ideas is...
> type Uncontrolled (<>) is abstract tagged limited private;
> with procedure Finalize (Object : in out Uncontrolled);
>package Add_Finalization is
> type Controlled is new Uncontrolled with private;
> type Component (Parent : access Controlled) is new
> Ada.Finalization.Limited_Controlled with null record;
> type Controlled is new Uncontrolled with record
> Controller: Component (Controlled'Access);
> end record;
> procedure Finalize (Object : in out Component);
Now I've really tried hard to find a solution for the unlimited type, but
the only one I found is an ugly solution to the problem.
Using a global pointer to intermediately store the access value defeats the
idea to keep everything hidden inside the object.
What is more: In a multi-tasking environment, this cannot safely work!
But the big problem is: How to get the access value of the object just
finalized before into Adjust?
See the remarks in the AARM 7.6 (17a..e). Adjust just knows NOTHING about
type Uncontrolled (<>) is abstract tagged private;
with procedure Finalize (Object: in out Uncontrolled);
package Add_Finalization is
type Controlled is new Uncontrolled with private;
type Controlled_Ptr is access all Controll
type Component is new Ada.Finalization.Controlled with record
type Controlled is new Uncontrolled with record
Controller: Component := (Ada.Finalization.Controlled with
procedure Adjust (Object: in out Component);
procedure Finalize (Object: in out Component);
package body Add_Finalization.To_Uncontrolled is
procedure Adjust (Object: in out Component) is
Object.Parent := Ugly_Store; -- follows directly a call of Finalize
procedure Finalize (Object: in out Component) is
Ugly_Store := Object.Parent; -- in an assignment A := B; this just
Finalize (Uncontrolled (Object.Parent.all)); -- the call of Adjust
I've just some more questions about the whole concept. Let's assume the above
package Generations is
type Root is abstract tagged null record;
procedure Identify_Yourself (X: in out Root) is abstract;
type Parent is new Root with record
procedure Identify_Yourself (X: in out Parent);
type Derived is new Parent with record
-- procedure Identify_Yourself (X: in out Derived);
procedure Finalize (X: in out Derived);
package Add_Finalization_To_Derived is
new Add_Finalization (Derived, Finalize);
-- Is this inherited?
-- procedure Identify_Yourself (X: in out Controlled);
-- By what mechanism does Ada manage to derive Identify_Yourself for the
-- Add_Finalization_To_Derived.Controlled and Final?
-- Inside package Add_Finalization, Uncontrolled is abstract and no
-- except Finalize are known to the generic.
type Final is new Controlled with record
-- Is this inherited?
-- procedure Identify_Yourself (X: in out Final);
[log in to unmask]