TEAM-ADA Archives

Team Ada: Ada Programming Language Advocacy

TEAM-ADA@LISTSERV.ACM.ORG

Options: Use Classic View

Use Monospaced Font
Show Text Part by Default
Show All Mail Headers

Topic: [<< First] [< Prev] [Next >] [Last >>]

Print Reply
Tucker Taft <[log in to unmask]>
Wed, 13 May 1998 10:36:05 -0400
text/plain (101 lines)
> ...
> Ok, so X gets Initialize'd, and the aggregate as a whole
> does not.  I can see why this would apply to deferred
> constants, but why would it apply to all objects
> initialized with aggregates and all aggregates?

Think of an aggregate like a non-default constructor in C++.
The aggregate/constructor must specify the value you want for every field.
The values should be those that are OK to be seen by the destructor.
Think of "Initialize" like the default constructor in C++.  Note the
"redundancy" in both C++ and Ada 95 here between default constructors and
non-default constructors.  Both must set up the fields the way
you want them to be seen by the destructor.

> ...
> This is not at all clear.  In this case it seems
> you are saying that the X part of Null_Y will not
> be finalized automatically, though it was initialized
> so, and that a finalization is performed for Null_Y,
> though Null_Y was never initialized or adjusted.
> This runs counter to my expectations, and I suppose
> it will do so for anyone I teach who comes from a
> C++ background.  I was making a gratuitous assumption:
> Initialize/Adjust is always symmetrical with respect
> to Finalize.

An aggregate is like a C++ non-default constructor.
Adjust is (somewhat) like a C++ copy constructor.
And Initialize is like a C++ default (parameterless) constructor.

So Finalize, which is essentially a destructor "balances" any
one of these kinds of constructors -- aggregate, Adjust, or Initialize.

> ...
> Does this mean, then, that
>
>     X := (Controlled with null record);
>
> does not call Adjust for the temporary object created
> by the evaluation of the aggregate?  I thought for
> sure that was the point of Norm Cohen's discussion.

This is an assignment *statement* to X rather than an initialization
of X.  Adjust is called on X after copying the temp object's value onto it.
Then the temp object needs to be finalized.  The temp object was
"constructed" by the aggregate.  It is conceivable that after
finalizing the LHS "X" the compiler might be clever enough to
"construct" the aggregate value directly in X.  This cleverness
is required for *initializations* of a variable, as opposed to
assignments.  Note that for an initialization, there is no
finalization of the LHS, because the variable doesn't exist prior
to the initialization.

> ...
> But this is what I was complaining about before: the
> activity you are doing here is a hand-coded version
> of what is contained in the Init/Adj routines.
> Essentially the same thing is being done in two places
> and in different ways, duplicating effort and
> introducing a maintenence problem.  Furthermore, this
> hand-initialization affects only the value contained in
> the object, and therefore cannot do anything "extra"
> that you would like performed at object-creation time.

Remember that each aggregate is like a non-default C++ constructor.
Just like in C++, all "constructors" must initialize the object
so that it is ready for the destructor.

> It looks like this gets back to my original point:
> apparently there is no way to ensure that a user-
> defined activity takes place exactly at the point
> of object creation in all cases in such a way that
> a corresponding Init or Adj is called for each
> Finalize.

To reiterate, Initialize corresponds to default construction, Adjust
to copy construction, and an aggregate to non-default construction.
By making the type private or a private extension, you ensure that
aggregates only appear inside the package defining the abstraction.
Each such aggregate represents a separate constructor.

> ... I can solve my problem: make the Controlled
> aspect of my type private so that no external
> aggregates can be created "improperly"; ...

You certainly have to make all contolled types private
or a private extension, or else you will inevitably lose control.
Note that you can use a controlled object as a component of
some other object, including a visible record.

In general, you should make the controlled part as small as possible,
rather than making a whole record controlled when only one piece of it
needs full control.

> Thanks once again.
>
> Stanley Allen
> mailto:[log in to unmask]

-Tucker Taft  [log in to unmask]

ATOM RSS1 RSS2