comp.lang.ada
 help / color / mirror / Atom feed
* Constructors/Destructors in Ada95
@ 2000-10-18  0:00 Francois Godme
  2000-10-19  0:00 ` Marin David Condic
                   ` (2 more replies)
  0 siblings, 3 replies; 35+ messages in thread
From: Francois Godme @ 2000-10-18  0:00 UTC (permalink / raw)


Hi all,

Where can I find articles, papers, or posted messages explaining me the
reasons for the lack of support for Constructors/Destructors directly in
the language. I have heard that, in 1995, Tucker Taft on c.l.a posted
several messages on this very subject.

I went to www.deja.com but they say that temporarily it is not possible
to consult archives past 1999. Is there an Ada web site which archives
our group?

Thanks.






^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-18  0:00 Constructors/Destructors in Ada95 Francois Godme
  2000-10-19  0:00 ` Marin David Condic
  2000-10-19  0:00 ` Ted Dennison
@ 2000-10-19  0:00 ` tmoran
  2000-10-19  0:00   ` Francois Godme
  2 siblings, 1 reply; 35+ messages in thread
From: tmoran @ 2000-10-19  0:00 UTC (permalink / raw)


> lack of support for Constructors/Destructors directly in the language.
  What do you feel missing from Ada.Finalization?




^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-19  0:00 ` tmoran
@ 2000-10-19  0:00   ` Francois Godme
  2000-10-19  0:00     ` Ted Dennison
                       ` (2 more replies)
  0 siblings, 3 replies; 35+ messages in thread
From: Francois Godme @ 2000-10-19  0:00 UTC (permalink / raw)


tmoran@bix.com a �crit :

> > lack of support for Constructors/Destructors directly in the language.
>   What do you feel missing from Ada.Finalization?

No one can give me pointers to the true sources?

I did not want to start arguing over this question in a newsgroup. My
English output flow is not sufficient to sustain long debates.

To Ted Dennison, I will say that before I dared to go out on the net, I
looked at my in-house documentation. That is the one you can find with the
gnat rpms for Linux made by J�ergen Pfeiffer (arm, rationale and Ada style
guide).

This WHY question is the exception to the rule that every WHY question has
an answer in the rationale.

grep -il constructor /usr/share/ada/html/rat95html-1.07/*
/usr/share/ada/html/rat95html-1.07/rat95-p3-a.html
/usr/share/ada/html/rat95html-1.07/rat95-p3-g.html

Two non relevant answers.

$ grep -il destructor /usr/share/ada/html/rat95html-1.07/*

No answer at all.


To Marin David Condic, I will say that I went to his web site and that his
constructor does not respect the Ada style guide which states: "Avoid
declaring a constructor as a primitive abstract operation."

Constructors are a pain to inherit.

To Tom Moran, I will say that the problem in the Ada.Finalization package
is the Initialize procedure.

The procedures Adjust and Finalize do not cause any problems. But the
Initialize procedure does not respect the Ada style guide for the same
reason as above. The Initialize procedure is inherited. And worst, besides
the object itself to initialize, there are no other parameters passed to
initialize the object. It is like if in C++, all classes were forced to
have a default constructor and the instances were first initialized to
useless values.

That's why the Ada style guide goes on to state: "Consider splitting the
initialization and construction of an object."






^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-19  0:00   ` Francois Godme
@ 2000-10-19  0:00     ` Ted Dennison
  2000-10-20  0:00     ` Tucker Taft
  2000-10-22  0:00     ` rwilson007007
  2 siblings, 0 replies; 35+ messages in thread
From: Ted Dennison @ 2000-10-19  0:00 UTC (permalink / raw)


In article <39EF5431.BF4CD793@bigfoot.com>,
  Francois Godme <fgodme@bigfoot.com> wrote:
> This WHY question is the exception to the rule that every WHY question
> has an answer in the rationale.
>
> grep -il constructor /usr/share/ada/html/rat95html-1.07/*
> /usr/share/ada/html/rat95html-1.07/rat95-p3-a.html
> /usr/share/ada/html/rat95html-1.07/rat95-p3-g.html
>
> Two non relevant answers.
>
> $ grep -il destructor /usr/share/ada/html/rat95html-1.07/*
>
> No answer at all.

There is an entire section on this topic at
http://www.adaic.org/standards/95rat/RAThtml/rat95-p2-7.html#4 . You
probably didn't find it because the proper Ada terms are "Initilization"
and "Finalization", not "Construction" and "Destruction".

However, I will admit that it doesn't say much about *why* the package
approach was chosen over other possible approaches to the same problem.
The best I see in there is:
---
A number of different approaches were considered and rejected
during the evolution of Ada 95. The final solution has the merit of
allowing user-defined assignment and also solves the problem
of returning limited types mentioned in the previous section.
---

Its possible the bit "mentioned in the previous section" will shed some
more light on the issue, but I doubt it.


--
T.E.D.

http://www.telepath.com/~dennison/Ted/TED.html


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-18  0:00 Constructors/Destructors in Ada95 Francois Godme
  2000-10-19  0:00 ` Marin David Condic
@ 2000-10-19  0:00 ` Ted Dennison
  2000-10-19  0:00 ` tmoran
  2 siblings, 0 replies; 35+ messages in thread
From: Ted Dennison @ 2000-10-19  0:00 UTC (permalink / raw)


Francois Godme wrote:

> Where can I find articles, papers, or posted messages explaining me the
> reasons for the lack of support for Constructors/Destructors directly in
> the language. I have heard that, in 1995, Tucker Taft on c.l.a posted
> several messages on this very subject.

The Ada95 Rationale would be a good place to look for all the "Why?"
questions you might have. Its online at
http://www.adaic.org/standards/95rat/RAThtml/rat95-contents.html
--
T.E.D.

Home - mailto:dennison@telepath.com  Work - mailto:dennison@ssd.fsi.com
WWW  - http://www.telepath.com/dennison/Ted/TED.html  ICQ  - 10545591






^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-18  0:00 Constructors/Destructors in Ada95 Francois Godme
@ 2000-10-19  0:00 ` Marin David Condic
  2000-10-19  0:00 ` Ted Dennison
  2000-10-19  0:00 ` tmoran
  2 siblings, 0 replies; 35+ messages in thread
From: Marin David Condic @ 2000-10-19  0:00 UTC (permalink / raw)


You sort of have the means to get there with Ada.Finalization. Somewhere
between Initialize/Finalize/Adjust and other normal language features, you
have all the same capabilities of C++'s Constructors/Destructors. I've got
some code comparing the two language's mechanisms on my web page. See:
http://www.mcondic.com/ and look for The C++ To Ada Translation Page.

MDC

Francois Godme wrote:

> Hi all,
>
> Where can I find articles, papers, or posted messages explaining me the
> reasons for the lack of support for Constructors/Destructors directly in
> the language. I have heard that, in 1995, Tucker Taft on c.l.a posted
> several messages on this very subject.
>
> I went to www.deja.com but they say that temporarily it is not possible
> to consult archives past 1999. Is there an Ada web site which archives
> our group?
>
> Thanks.

--
======================================================================
Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
Visit my web site at:  http://www.mcondic.com/

    "Giving money and power to Government is like giving whiskey
    and car keys to teenage boys."

        --   P. J. O'Rourke
======================================================================






^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-20  0:00     ` Tucker Taft
@ 2000-10-20  0:00       ` Francois Godme
  2000-10-21  0:00         ` Marin David Condic
  2000-10-23  0:00       ` Francois Godme
  1 sibling, 1 reply; 35+ messages in thread
From: Francois Godme @ 2000-10-20  0:00 UTC (permalink / raw)


Tucker Taft a �crit :

> It is a mistake to think that the Initialize procedure
> represents Ada's "constructor" feature.  As you recognize
> below, Initialize is the rough equivalent of the default
> constructor.  For any other kind of constructor, you simply
> write a function, or procedure with an [in] out parameter.
> Ada also has a builtin constructor to simplify the
> creation of these user-defined constructors, namely an aggregate
> (array, record, or record extension).  This is available
> for non-limited types, in places where the type is
> visible (e.g. inside the package where it is declared).
>
> An aggregate constructor can be combined with dynamic
> storage allocation, via an initialized allocator.
>

Record aggregates are neat but can only be used in a white box approach on
non-limited types. True, non-limited types can be initialized by functions but
you have to be careful to not make these functions primitive operations. By
using a 'class attribute on the return parameter type for example.

> For (inherently) limited types, non-default construction must be
> done essentially one component at a time, even when inside
> the package where the type is defined.  Of course, from outside
> the package, an appropriate procedure would be called to
> invoke the user-chosen construction operation, and that
> procedure would take care of the appropriate component-by-
> component actions.
>

Yes, but the drawback is that instances of limited types cannot be declared
constant when they should be. In C++, instances of classes with private
operator= and private operator== can be constant.

> Initialize is exactly the part of the default constructor,
> over and above the default initialization specified within
> the type declaration itself.  If the type extension adds
> more components that have default initialization, these
> default initializations will occur, even if Initialize is
> inherited.  In fact, I would generally recommend that
> programmers minimize the use of Initialize, if they can
> do it all with per-component default initialization.
>

Yes, they serve the same purpose with almost the same power. Constructors in
C++ have another feature unknown in Ada which allows the creation of constant
member attributes. It applies to any type. Not to a limited set of types which
can be used as record discriminants.






^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-19  0:00   ` Francois Godme
  2000-10-19  0:00     ` Ted Dennison
@ 2000-10-20  0:00     ` Tucker Taft
  2000-10-20  0:00       ` Francois Godme
  2000-10-23  0:00       ` Francois Godme
  2000-10-22  0:00     ` rwilson007007
  2 siblings, 2 replies; 35+ messages in thread
From: Tucker Taft @ 2000-10-20  0:00 UTC (permalink / raw)


Francois Godme wrote:
> ...
> 
> To Tom Moran, I will say that the problem in the Ada.Finalization package
> is the Initialize procedure.

It is a mistake to think that the Initialize procedure
represents Ada's "constructor" feature.  As you recognize
below, Initialize is the rough equivalent of the default
constructor.  For any other kind of constructor, you simply
write a function, or procedure with an [in] out parameter.
Ada also has a builtin constructor to simplify the
creation of these user-defined constructors, namely an aggregate
(array, record, or record extension).  This is available
for non-limited types, in places where the type is
visible (e.g. inside the package where it is declared).  

An aggregate constructor can be combined with dynamic
storage allocation, via an initialized allocator.

For (inherently) limited types, non-default construction must be 
done essentially one component at a time, even when inside
the package where the type is defined.  Of course, from outside
the package, an appropriate procedure would be called to
invoke the user-chosen construction operation, and that
procedure would take care of the appropriate component-by-
component actions.

> 
> The procedures Adjust and Finalize do not cause any problems. But the
> Initialize procedure does not respect the Ada style guide for the same
> reason as above. The Initialize procedure is inherited. And worst, besides
> the object itself to initialize, there are no other parameters passed to
> initialize the object. It is like if in C++, all classes were forced to
> have a default constructor and the instances were first initialized to
> useless values.

Initialize is exactly the part of the default constructor,
over and above the default initialization specified within
the type declaration itself.  If the type extension adds
more components that have default initialization, these
default initializations will occur, even if Initialize is
inherited.  In fact, I would generally recommend that
programmers minimize the use of Initialize, if they can
do it all with per-component default initialization.

But the key point is not to think of "Initialize" as
a general purpose constructor.  It is simply the default
"constructor" (and really only part of that, given the
per-component defaults that are applied first).
"Regular" functions and procedures are used to do
any other "construction."
> 
> That's why the Ada style guide goes on to state: "Consider splitting the
> initialization and construction of an object."

They should probably say consider splitting
*default* initialization and *explicit* construction.
This is only really *necessary* for limited types.
For non-limited types, using a function to initialize
the object upon declaration/dynamic allocation is
quite appropriate.

-- 
-Tucker Taft   stt@averstar.com   http://www.averstar.com/~stt/
Technical Director, Commercial Division, AverStar (formerly Intermetrics)
(http://www.averstar.com/services/IT_consulting.html)  Burlington, MA  USA




^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-20  0:00       ` Francois Godme
@ 2000-10-21  0:00         ` Marin David Condic
  0 siblings, 0 replies; 35+ messages in thread
From: Marin David Condic @ 2000-10-21  0:00 UTC (permalink / raw)


Remember that Ada is not C++. You can pretty much get the same net effect of
constructors and destructors in Ada - but not in exactly the same way. So you
change the model instead. Since Ada doesn't treat assignment the same way as C++
and you don't have the same parameter features, you've got to work with what Ada
does provide and try not to make it look exactly like C++. The job does get done
and, IMHO, it is a lot less semantically messy when done in Ada as opposed to C++.

MDC

Francois Godme wrote:

> Yes, they serve the same purpose with almost the same power. Constructors in
> C++ have another feature unknown in Ada which allows the creation of constant
> member attributes. It applies to any type. Not to a limited set of types which
> can be used as record discriminants.

--
======================================================================
Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
Visit my web site at:  http://www.mcondic.com/

    "Giving money and power to Government is like giving whiskey
    and car keys to teenage boys."

        --   P. J. O'Rourke
======================================================================






^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-19  0:00   ` Francois Godme
  2000-10-19  0:00     ` Ted Dennison
  2000-10-20  0:00     ` Tucker Taft
@ 2000-10-22  0:00     ` rwilson007007
  2000-10-22  0:00       ` Francois Godme
  2 siblings, 1 reply; 35+ messages in thread
From: rwilson007007 @ 2000-10-22  0:00 UTC (permalink / raw)


in order to achieve the same effect as constructor arguments in c++ it
is helpful to define an attributes class for each application-object
class (with the same inheritance pattern as the application classes).
the attributes class tagged record contains a field for each application
-class tagged record field requiring explicit initialization.

then, define the base class tagged record for your
application-object classes with a classwide access value to a
constant attributes class instance as one of its members.

finally, the base class constructor reads the initial-attributes values
for its attributes member from config files (for example). the
inheriting classes then look-up the appropriate initial values in
This.Attributes (for "Initialize (This : in out access Object)")....

another way is to is enclose your classes in generic packages with the
generic formal parameters corresponding to constructor arguments.
however, this would seem to force a singleton pattern.

--rwilson


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-22  0:00     ` rwilson007007
@ 2000-10-22  0:00       ` Francois Godme
  2000-10-24  0:00         ` rwilson007007
  0 siblings, 1 reply; 35+ messages in thread
From: Francois Godme @ 2000-10-22  0:00 UTC (permalink / raw)


rwilson007007@my-deja.com a �crit :

> in order to achieve the same effect as constructor arguments in c++ it
> is helpful to define an attributes class for each application-object
> class (with the same inheritance pattern as the application classes).
> the attributes class tagged record contains a field for each application
> -class tagged record field requiring explicit initialization.
>
> then, define the base class tagged record for your
> application-object classes with a classwide access value to a
> constant attributes class instance as one of its members.
>
> finally, the base class constructor reads the initial-attributes values
> for its attributes member from config files (for example). the
> inheriting classes then look-up the appropriate initial values in
> This.Attributes (for "Initialize (This : in out access Object)")....
>
> another way is to is enclose your classes in generic packages with the
> generic formal parameters corresponding to constructor arguments.
> however, this would seem to force a singleton pattern.

To rwilson, I will say that I am not sure that I fully undestand its
proposal. For instance, I am not sure how different instances get
initialized with different values in these scheme. Also, I am not sure if
it needs not twice the memory, once in the application classes and once in
the initializing classes. Anyway, I admit that for exemple with a public
access discriminant to a string in the base class, the Initialize
procedures could lookup somewhere, somehow with this name for values to
initialize the instance. I find it too difficult to handle and prefer
Tucker Taft's direct manner with non-primitive functions returning
initialized instances for non-limited types and non-primitive procedures
for limited types.


Marin David Condic has said:
"Remember that Ada is not C++. You can pretty much get the same net effect
of
constructors and destructors in Ada - but not in exactly the same way. So
you
change the model instead. Since Ada doesn't treat assignment the same way
as C++
and you don't have the same parameter features, you've got to work with
what Ada
does provide and try not to make it look exactly like C++. The job does get
done
and, IMHO, it is a lot less semantically messy when done in Ada as opposed
to C++."


To Marin David Condic, I will say, well, recently, the model has been
changed to make it look more like C++ by adding the "with type" feature
which was felt lacking after feature comparisons with Java and C++. Some
people complained they couldn't get the work done with what Ada provides.

I take C++ as an exemple because C++ got inspired a lot by Ada83 in my
opinion. C++ has pragmas, inlined routines, generics (templates), public
and private parts (as well as protected parts), parameter passing modes,
default parameters, constant objects, operators and methods overloading,
(poor) enumeration types, exceptions, renamings (you can think of C++
references as renamings of objects.). C++ has also well-thought
constructors. No pun intended.





^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-20  0:00     ` Tucker Taft
  2000-10-20  0:00       ` Francois Godme
@ 2000-10-23  0:00       ` Francois Godme
  2000-10-24  0:00         ` Ray Blaak
  1 sibling, 1 reply; 35+ messages in thread
From: Francois Godme @ 2000-10-23  0:00 UTC (permalink / raw)


I would like to add some other arguments not yet expressed:

   * against the non-primitive procedures used as constructors of limited
     instances like in Tucker Taft's proposal,
   * against the Adjust procedure and
   * against the Finalize procedure.

I. Non-primitive procedures used as constructors of limited instances:
As limited instances can't be initialized with record aggregates, it is
possible to write code which forgets to initialize all record fields. It was
already the case in Ada83 but only in the horizontal plane. With procedures, it
can now get wrong in the vertical plane along the class hierarchy if one forgot
to call one of the initializing procedures of its immediate super-class.
Programmers have also to remember to call the super-class procedure first as a
precaution before initializing extension record fields. Nothing insurmountable
I admit. If the language had constructors, the compiler could warn me when I
forgot something in the horizontal or the vertical plane. This will increase
safety.

This doesn't apply to non-limited types if they are initialized only with
aggregates and functions. No procedures.

II.The Adjust procedure:
Efficiency concerns may be raised against the sequence: Finalize (Target);
shallow copy Source into Target; Adjust (Target);.

In the Adjust procedure, control is given to perform, for instance, a deep copy
of Source into Target. One can easily devise situations where Finalize of
Target will have to deallocate memory which will be immediately needed and
reallocated by Adjust of Target.

III. The Finalize procedure:
The programmers are responsible in the Finalize procedure to call last the
immediate super-class Finalize procedure. As the notion of immediate
super-class does not exist in the language, it is not possible to write code
that will always call the Finalize procedure of the immediate super-class.





^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-22  0:00       ` Francois Godme
@ 2000-10-24  0:00         ` rwilson007007
  0 siblings, 0 replies; 35+ messages in thread
From: rwilson007007 @ 2000-10-24  0:00 UTC (permalink / raw)


F. Godme:
> proposal. For instance, I am not sure how different instances get
> initialized with different values in these scheme. Also, I am not sure

the scheme i had in mind is sometimes known as a "factory pattern" -
have a generic create & destroy procedures which take a string name,
look for that name in a file, retrieve attributes associated with that
name in the file, and then invoke ada.finalization for the base class,
setting its attributes pointer for use in subsequent subclass initialize
invocations.

roughly, it goes like:
--#
package Object_Life_Cycle is

  generic
    type Object is tagged abstract private;

  package Factory is

    type Ref is access all Object'Class;

    -- Create will invoke "This := new Object" (triggering
    -- Ada.Finalization.Initialize) in its body
    -- (note - 'Name' is used to lookup attributes from a file)
    function Create (Name : in String) return Ref;

    function Destroy (This : in out Ref);

  end Factory;

end Object_Life_Cycle;
--#
-- in another ada module
--#
package Attributes_Base_Class is

    type Object is abstract tagged with
       record
         Name : constant String;
       record;
   end Base;

   type Ref is access all Object'Class;

end Attributes_Base_Class;
--#
-- et in another ada module...
--#
with Attributes_Base_Class;
with Ada.Finalization;

package Base_Class is

  type Object is new Ada.Finalization.Controlled with
    record
      Attributes : Attributes_Base_Class.Ref;
  end Object;

  type Ref is access all Object'Class;

  private
    procedure Initialize (This : in out Object);

    procedure Finalize (This : in out Object);

end Base_Class;
--#
--et in another ada module
--#
with Attributes_Base_Class;
with Base_Class;
with Object_Life_Cycle;

package My_Class is

   type Colors is (Red, Yellow, Green, Blue, White, Black);

   type Attributes is new Attributes_Base_Class.Object with
     record
       Height : Integer;
       Width : Integer;
       Length : Integer;
       Depth : Integer;
       Mass : Integer;
       Color : Colors;
       Age : Duration;
     end record;

   type Object is private;
   type Ref is access all Object'Class;

   -- method declarations go here
   function Age (This : in Ref) return Integer;
   function Color (This : in Ref) return Colors;
   procedure Evolve (This : in Ref);

   package Factory is new Object_Life_Cycle.Factory
    (Object => Object);

   private
      type Object is new Base_Class.Object with
        record
          Actual_Age : Duration;
          Current_Color : Colors;
          Power : Integer;
        end record;

      procedure Initialize (This : in out Object);
      procedure Finalize (This : in out Object);

end My_Class;
--#
-- et in ada_main
--#
with My_Class;

procedure Ada_Main is

   My_Object : My_Class.Ref;

   Current_Age : Duration;
   Actual_Color : My_Class.Colors;

   begin
    My_Object := My_Class.Factory.Create (Name => "MY_FIRST_OBJECT");

    My_Object_Life:
    loop -- forever

       My_Class.Evolve (This => My_Object);

       Current_Age := My_Class.Age (This => My_Object);
       Actual_Color := My_Class.Color (This => My_Object);

       Text_Io.Put_Line ("My" & My_Class.Colors'Image (Actual_Color) &
                         " Object is" & Duration'Image (Current_Age) &
                         " milliseconds old...");

       if Current_Age > 25.0 then
         My_Class.Factory.Destory (This => My_Object);
         Text_Io.Put_Line ("My_Object is dead!");
         exit My_Object_Life;
       end if;
    end loop My_Object_Life;

end Ada_Main;

--#
-- et (finally) in a plain text file:
# configuration parameters for named objects go here
My_First_Object : My_Class.Attributes;
My_First_Object.Height = 100
My_First_Object.Width = 200
My_First_Object.Length = 40
My_First_Object.Depth = -20
My_First_Object.Mass = 0
My_First_Object.Color = My_Class.Red
My_First_Object.Age = 0.0



Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-23  0:00       ` Francois Godme
@ 2000-10-24  0:00         ` Ray Blaak
  2000-10-25  0:00           ` Marin David Condic
                             ` (2 more replies)
  0 siblings, 3 replies; 35+ messages in thread
From: Ray Blaak @ 2000-10-24  0:00 UTC (permalink / raw)


Francois Godme <fgodme@bigfoot.com> writes:

> I. Non-primitive procedures used as constructors of limited instances: As
> limited instances can't be initialized with record aggregates, it is possible
> to write code which forgets to initialize all record fields.

Forgetting to initialize a field is equivalent to using a default constructor,
no? In that case the Initialize routine can cover it.

If not field is not a tagged type, either a default component assignment can
cover it, or if limited, the compiler should flag an error that the item is not
created.

I do grant you, however, that C++'s constructors are nice for forcing an item
to be created in only valid ways.

> II.The Adjust procedure: Efficiency concerns may be raised against the
> sequence: Finalize (Target); shallow copy Source into Target; Adjust
> (Target);.

I really would like to be able to do:

  procedure ":="(target : in out T; source : in T);

so as to have complete control over what is happening. I vaguely recall some
rationale from the Ada 9X discussions for why user-defined assignment per se
was not incorporated. Does anyone remember?

> III. The Finalize procedure:
> The programmers are responsible in the Finalize procedure to call last the
> immediate super-class Finalize procedure. As the notion of immediate
> super-class does not exist in the language, it is not possible to write code
> that will always call the Finalize procedure of the immediate super-class.

Not just in Ada. This bug has bitten me in C++ too often during redesign
times. Java's "super" and Delphi's "inherited" keywords neatly make this issue
go away.

Anyone know of a reason why "super" would not be a good idea for Ada 0X?

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
blaak@infomatch.com                            The Rhythm has my soul.




^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-25  0:00           ` Marin David Condic
@ 2000-10-25  0:00             ` dmitry6243
  2000-10-25  0:00               ` mark.biggar
  2000-10-25  0:00               ` Pascal Obry
  2000-10-27  7:12             ` Ray Blaak
  1 sibling, 2 replies; 35+ messages in thread
From: dmitry6243 @ 2000-10-25  0:00 UTC (permalink / raw)


In article <39F6D201.73C006FA@acm.org>,
  Marin David Condic <mcondic.nospam@acm.org> wrote:
> Ray Blaak wrote:
>
> > I really would like to be able to do:
> >
> >   procedure ":="(target : in out T; source : in T);
> >
> > so as to have complete control over what is happening. I vaguely recall some
> > rationale from the Ada 9X discussions for why user-defined assignment per se
> > was not incorporated. Does anyone remember?
>
> Does a
> statement like: "X < Y ;" make sense in Ada?) As a procedure, you'd have to allow
> procedures to have symbol names - which opens up a whole can of worms. Further, it
> would mean allowing "infix procedures" which is hard to make sense of - or at least
> could make programs look really strange.

It would be nice (it is in my private Ada to-do list for a long time):

function "*" (Left, Right : Matrix) return Matrix;  -- Produces a new object
procedure "*" (Left : in out Matrix; Right : Matrix);  -- Multiplies Left to
Right "in-place"

So I would count it as an advantage. There is another. If you have

procedure ":="(target : in out T; source : in T);

then your assignment may take a look on the left-side object before its
destruction. Ada's Adjust is much more (IMO too much) specialized.

> I'm sure there are dozens of other reasons why it was decided not to provide a
> means of letting the user define assignment. I'd think it would require perverting,
> warping and twisting language concepts too much.

I think that the major reason was the decision to limit user defined
assigments by Controlled types. Doing so you must drop ":=" form, which
ontherwise would permanently remind you that actually all types might be
assigned (:-))

> (Look at the semantics of C++
> construction/destruction sometime - especially as it applies to function parameters
> - and see what an abomination that can become! :-)

So let's show them how to do it right (:-))

--
Regards,
Dmitry Kazakov


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-25  0:00             ` dmitry6243
@ 2000-10-25  0:00               ` mark.biggar
  2000-10-26 11:44                 ` dmitry6243
  2000-10-26 21:31                 ` Tucker Taft
  2000-10-25  0:00               ` Pascal Obry
  1 sibling, 2 replies; 35+ messages in thread
From: mark.biggar @ 2000-10-25  0:00 UTC (permalink / raw)


In article <8t6pi9$9s8$1@nnrp1.deja.com>,
  dmitry6243@my-deja.com wrote:
> In article <39F6D201.73C006FA@acm.org>,
>   Marin David Condic <mcondic.nospam@acm.org> wrote:
> > Ray Blaak wrote:
> >
> > > I really would like to be able to do:
> > >
> > >   procedure ":="(target : in out T; source : in T);
> > >
> > > so as to have complete control over what is happening. I vaguely
recall some
> > > rationale from the Ada 9X discussions for why user-defined
assignment per se
> > > was not incorporated. Does anyone remember?
> >
> > Does a
> > statement like: "X < Y ;" make sense in Ada?) As a procedure, you'd
have to allow
> > procedures to have symbol names - which opens up a whole can of
worms. Further, it
> > would mean allowing "infix procedures" which is hard to make sense
of - or at least
> > could make programs look really strange.
>
> It would be nice (it is in my private Ada to-do list for a long time):
>
> function "*" (Left, Right : Matrix) return Matrix;  -- Produces a new
object
> procedure "*" (Left : in out Matrix; Right : Matrix);  -- Multiplies
Left to
> Right "in-place"
>
> So I would count it as an advantage. There is another. If you have
>
> procedure ":="(target : in out T; source : in T);
>
> then your assignment may take a look on the left-side object before
its
> destruction. Ada's Adjust is much more (IMO too much) specialized.
>
> > I'm sure there are dozens of other reasons why it was decided not to
provide a
> > means of letting the user define assignment. I'd think it would
require perverting,
> > warping and twisting language concepts too much.
>
> I think that the major reason was the decision to limit user defined
> assigments by Controlled types. Doing so you must drop ":=" form,
which
> ontherwise would permanently remind you that actually all types might
be
> assigned (:-))

One of the problems with this proposal (redefineing ":=") is that
you would have to define Initialize, Adjust and Finialize anyway
as you need them to implement value parameter passing, temporary
creation and function return values correctly.  Each of those is
like assingment, but not exactly the same being, built out of the
three primitives in different ways.  So it makes more sense to just
define the three primitives and have the compiler generate
standard usage sequences then to redefine ":=" and have strange
and hard to understand things happen.

There's a reason that C++ has several types of constructors and in
many ways the Ada mechanism is simpler.

--
Mark Biggar
mark.biggar@trustedsyslabs.com


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-24  0:00         ` Ray Blaak
  2000-10-25  0:00           ` Marin David Condic
@ 2000-10-25  0:00           ` Francois Godme
  2000-10-27 18:11           ` Francois Godme
  2 siblings, 0 replies; 35+ messages in thread
From: Francois Godme @ 2000-10-25  0:00 UTC (permalink / raw)


Ray Blaak a �crit :

>
> I really would like to be able to do:
>
>   procedure ":="(target : in out T; source : in T);
>
> so as to have complete control over what is happening. I vaguely recall some
> rationale from the Ada 9X discussions for why user-defined assignment per se
> was not incorporated. Does anyone remember?
>

An alternative would be inside Ada.Finalization

procedure Deep_Copy (Source : access Controlled; Target : access Controlled);

procedure Shallow_Copy (Source : in Controlled'Class; Target : out
Controlled'Class);

Deep_Copy is an overridible primitive whose default implementation is to call
Shallow_Copy to copy Source into Target if Source and Target are different access
values and to do nothing otherwise.

Shallow_Copy is a class-wide procedure provided by the Ada run-time which avoids
to fall into infinite recursion
when writing "Target.all := Source.all;". Instead, one writes "Shallow_Copy
(Source.all, Target.all);".






^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-24  0:00         ` Ray Blaak
@ 2000-10-25  0:00           ` Marin David Condic
  2000-10-25  0:00             ` dmitry6243
  2000-10-27  7:12             ` Ray Blaak
  2000-10-25  0:00           ` Francois Godme
  2000-10-27 18:11           ` Francois Godme
  2 siblings, 2 replies; 35+ messages in thread
From: Marin David Condic @ 2000-10-25  0:00 UTC (permalink / raw)


Ray Blaak wrote:

> I really would like to be able to do:
>
>   procedure ":="(target : in out T; source : in T);
>
> so as to have complete control over what is happening. I vaguely recall some
> rationale from the Ada 9X discussions for why user-defined assignment per se
> was not incorporated. Does anyone remember?

I don't know about the Ada 9X discussions specifically, but if you think about it,
there are a lot of obvious problems with trying to redefine ":=". The biggest
problem is that it is not a subprogram - it is a primitive feature of the language.
I believe this might be an example of Godel's Theorem. There are some features of
the language (any language) that cannot be expressed in the language itself. As a
"function" it would require that a) the left parameter be treated as "out" and b)
that the function need not return a result. (or that it could be ignored. Does a
statement like: "X < Y ;" make sense in Ada?) As a procedure, you'd have to allow
procedures to have symbol names - which opens up a whole can of worms. Further, it
would mean allowing "infix procedures" which is hard to make sense of - or at least
could make programs look really strange.

I'm sure there are dozens of other reasons why it was decided not to provide a
means of letting the user define assignment. I'd think it would require perverting,
warping and twisting language concepts too much. (Look at the semantics of C++
construction/destruction sometime - especially as it applies to function parameters
- and see what an abomination that can become! :-)
--
======================================================================
Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
Visit my web site at:  http://www.mcondic.com/

    "Giving money and power to Government is like giving whiskey
    and car keys to teenage boys."

        --   P. J. O'Rourke
======================================================================






^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-25  0:00             ` dmitry6243
  2000-10-25  0:00               ` mark.biggar
@ 2000-10-25  0:00               ` Pascal Obry
  2000-10-26  0:00                 ` dmitry6243
  1 sibling, 1 reply; 35+ messages in thread
From: Pascal Obry @ 2000-10-25  0:00 UTC (permalink / raw)



dmitry6243@my-deja.com writes:

> In article <39F6D201.73C006FA@acm.org>,
> 
> function "*" (Left, Right : Matrix) return Matrix;  -- Produces a new object
> procedure "*" (Left : in out Matrix; Right : Matrix);  -- Multiplies Left to
> Right "in-place"

I'am not an expert in this field but I really fail to see how it is possible
to multiply two matrix without creating a temporary one ! So I'am not sure
your example is a good one :)

Pascal.

-- 

--|------------------------------------------------------
--| Pascal Obry                           Team-Ada Member
--| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE
--|------------------------------------------------------
--|         http://perso.wanadoo.fr/pascal.obry
--|
--| "The best way to travel is by means of imagination"




^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-25  0:00               ` Pascal Obry
@ 2000-10-26  0:00                 ` dmitry6243
  0 siblings, 0 replies; 35+ messages in thread
From: dmitry6243 @ 2000-10-26  0:00 UTC (permalink / raw)


In article <uem14bvc6.fsf@wanadoo.fr>,
  Pascal Obry <p.obry@wanadoo.fr> wrote:
>
> dmitry6243@my-deja.com writes:
>
> > In article <39F6D201.73C006FA@acm.org>,
> >
> > function "*" (Left, Right : Matrix) return Matrix;  -- Produces a
new object
> > procedure "*" (Left : in out Matrix; Right : Matrix);  -- Multiplies
Left to
> > Right "in-place"
>
> I'am not an expert in this field but I really fail to see how it is
possible
> to multiply two matrix without creating a temporary one ! So I'am not
sure
> your example is a good one :)

It was about 15 years I wrote my last program for linear algebra. That
time memory was a treasure (:-)).

So I am not an expert too. In case of matrices one needs only one
row/column of scratch memory, which is of course better than an
allocation of the complete matrix.

And there are lots of special matrices used much oftener than general
dense matrices.

---
Regards,
Dmitry Kazakov


Sent via Deja.com http://www.deja.com/
Before you buy.




^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-25  0:00               ` mark.biggar
@ 2000-10-26 11:44                 ` dmitry6243
  2000-10-26 13:25                   ` Robert A Duff
  2000-10-26 17:55                   ` tmoran
  2000-10-26 21:31                 ` Tucker Taft
  1 sibling, 2 replies; 35+ messages in thread
From: dmitry6243 @ 2000-10-26 11:44 UTC (permalink / raw)


In article <8t6vhc$fmb$1@nnrp1.deja.com>,
  mark.biggar@trustedsyslabs.com wrote:
> In article <8t6pi9$9s8$1@nnrp1.deja.com>,
>   dmitry6243@my-deja.com wrote:
> > In article <39F6D201.73C006FA@acm.org>,
> >   Marin David Condic <mcondic.nospam@acm.org> wrote:
> > > Ray Blaak wrote:
> > >
> > > > I really would like to be able to do:
> > > >
> > > >   procedure ":="(target : in out T; source : in T);
> > > >
> > > > so as to have complete control over what is happening. I vaguely
> recall some
> > > > rationale from the Ada 9X discussions for why user-defined
> assignment per se
> > > > was not incorporated. Does anyone remember?
> > >
> > > Does a
> > > statement like: "X < Y ;" make sense in Ada?) As a procedure,
you'd
> have to allow
> > > procedures to have symbol names - which opens up a whole can of
> worms. Further, it
> > > would mean allowing "infix procedures" which is hard to make sense
> of - or at least
> > > could make programs look really strange.
> >
> > It would be nice (it is in my private Ada to-do list for a long
time):
> >
> > function "*" (Left, Right : Matrix) return Matrix;  -- Produces a
new
> object
> > procedure "*" (Left : in out Matrix; Right : Matrix);  -- Multiplies
> Left to
> > Right "in-place"
> >
> > So I would count it as an advantage. There is another. If you have
> >
> > procedure ":="(target : in out T; source : in T);
> >
> > then your assignment may take a look on the left-side object before
> its
> > destruction. Ada's Adjust is much more (IMO too much) specialized.
> >
> > > I'm sure there are dozens of other reasons why it was decided not
to
> provide a
> > > means of letting the user define assignment. I'd think it would
> require perverting,
> > > warping and twisting language concepts too much.
> >
> > I think that the major reason was the decision to limit user defined
> > assigments by Controlled types. Doing so you must drop ":=" form,
> which
> > ontherwise would permanently remind you that actually all types
might
> be
> > assigned (:-))
>
> One of the problems with this proposal (redefineing ":=") is that
> you would have to define Initialize, Adjust and Finialize anyway
> as you need them to implement value parameter passing, temporary
> creation and function return values correctly.  Each of those is
> like assingment, but not exactly the same being, built out of the
> three primitives in different ways.

Yes. However, actually it is 5 primitives:

Allocator (System.Storage_Pools),
Default constructor (Initialize),
Copy constructor ("memmove" + Adjust),
Destructor (Finalize),
Deallocator (System.Storage_Pools)

> So it makes more sense to just
> define the three primitives and have the compiler generate
> standard usage sequences then to redefine ":=" and have strange
> and hard to understand things happen.

Most of programs are making strange and and hard to understand things
(:-)).

Yes. The compiler would generate the default assigment out of the
primitives and the programmer would override it if he were not satisfied
with the result.

There are lot of pitfalls here, but Initialize-Adjust-Finalize is
neither free of them. I had got a very nasty bug when a controlled type
was passed by copy instead of by reference as I thought (or better to
say, didn't care).

> There's a reason that C++ has several types of constructors and in
> many ways the Ada mechanism is simpler.

One needs at least two constructors, one for initialization, another for
creating temporal values (for instance, when an object is passed by
copy). We have this in Ada, we have this in C++.

I see nothing wrong if Ada would offer an ability to have initializing
constructors with parameters too. When

X : String (80);

is legal, why:

X : MyType (Y, Z, 3.1415);

cannot be allowed in addition to famous:

X : MyType := +(Y, Z, 3.1415); -- (:-))

User defined aggregates could also be a nice feature.

--
Regards,
Dmitry Kazakov


Sent via Deja.com http://www.deja.com/
Before you buy.



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-26 11:44                 ` dmitry6243
@ 2000-10-26 13:25                   ` Robert A Duff
  2000-10-27  8:10                     ` dmitry6243
  2000-10-26 17:55                   ` tmoran
  1 sibling, 1 reply; 35+ messages in thread
From: Robert A Duff @ 2000-10-26 13:25 UTC (permalink / raw)


dmitry6243@my-deja.com writes:

> There are lot of pitfalls here, but Initialize-Adjust-Finalize is
> neither free of them. I had got a very nasty bug when a controlled type
> was passed by copy instead of by reference as I thought (or better to
> say, didn't care).

Controlled types are always passed by reference.

- Bob



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-26 11:44                 ` dmitry6243
  2000-10-26 13:25                   ` Robert A Duff
@ 2000-10-26 17:55                   ` tmoran
  2000-10-27  8:10                     ` dmitry6243
  1 sibling, 1 reply; 35+ messages in thread
From: tmoran @ 2000-10-26 17:55 UTC (permalink / raw)


>X : String (80);
>X : MyType (Y, Z, 3.1415);
 You can't do
X : String (3.1415);
 but you can do
X : MyType (Y, Z, 3);



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-25  0:00               ` mark.biggar
  2000-10-26 11:44                 ` dmitry6243
@ 2000-10-26 21:31                 ` Tucker Taft
  2000-10-27  8:46                   ` dmitry6243
  1 sibling, 1 reply; 35+ messages in thread
From: Tucker Taft @ 2000-10-26 21:31 UTC (permalink / raw)


mark.biggar@trustedsyslabs.com wrote:
> ...
> 
> One of the problems with this proposal (redefineing ":=") is that
> you would have to define Initialize, Adjust and Finialize anyway
> as you need them to implement value parameter passing, temporary
> creation and function return values correctly.  Each of those is
> like assingment, but not exactly the same being, built out of the
> three primitives in different ways.  So it makes more sense to just
> define the three primitives and have the compiler generate
> standard usage sequences then to redefine ":=" and have strange
> and hard to understand things happen.

This is part of the reason we did not allow the user
to directly define ":=".  Another important reason has to
do with assignment of composite objects (e.g. records
and arrays) containing objects with user-defined
assignment.  One desirable feature is that the assignment
for a record, for example, is defined in terms of the
assignment of its individual components.  Unfortunately,
there are cases of record assignment in Ada where
the left-hand-side doesn't contain a component that
the right-hand-side does.  This happens if the left-hand-side
is an unconstrained record with discriminants, and the
right-hand-side happens to have different values for the
discriminants than the values of the left-hand-side.
As a result of the assignment, some components of the
left-hand-side may disappear, and some may come into existence.

For example:

    type Rec(B : Boolean := False) is record
        X : Cool_Controlled_Type;
        case B is
            when True =>
               Y : Fancy_Controlled_Type;
            when False =>
               Z : Another_Controlled_Type;
        end case;
    end record;

    R1 : Rec;  -- Defaults to B => False
    R2 : Rec(B => True);

     ...

    R1 := R2;  -- R1.Z disappears, R1.Y is created,
               --  R1.X overwritten

It would be tricky at best to define how or whether
user-defined ":=" for Cool_, Fancy_, and Another_Controlled_Type
should be used in the above case.  However, with the
user-defined operations broken down into Finalize and Adjust,
it is relatively straightforward to specify what happens:
R1.Z is finalized, R1.Y is adjusted after copying from R2.Y,
and R1.X is first finalized, and then adjusted after copying
from R2.X.

One viable semantics would be to specify that user-defined
assignment is used only for those cases where the component
already exists, and is being overwritten, and finalize
or adjust is used for the other cases.  That could work,
though it would prevent using block copy.  With the current
approach, block copy can be used to actually copy the "bits"
from R2 to R1, so long as any appropriate finalizations
are done before the copy, and any appropriate adjusts are
done afterward.  If the record has a bunch of non-controlled
components, then being able to use block copy might be seen
as an important advantage of the Ada 95 approach. 

Another nice feature of the current mechanism is that the 
compiler can create a single "whole record finalize" and another
"whole record adjust" procedure, which are simply "roll ups"
of the per-component finalize/adjust operations, possibly with
an implicit "case" statement based on the current value of
the discriminants.  An assignment statement would then
involve a call on the whole-record finalize, followed
by a block copy, followed by a call on the whole-record adjust.
(Also note that an explicit initialization in a declaration
"looks like" an assignment statement, but it couldn't use
the user-defined assignment, because the left-hand side isn't
yet initialized.  It really just needs a copy and adjust.
No finalizes should be performed.)

Creating an equivalent "whole-record-assign" rollup would
certainly be possible, though the details of such a routine
for a record type like "Rec" above would be pretty painful.
You would compare the values of the discriminants of the
left and right sides, and then depending on the various
possibilities, one would do one of three things for each
component: finalize LHS component, copy RHS into LHS and adjust,
or user-defined-assign RHS into LHS.  The order of doing 
this would be somewhat tricky, and there are sometimes 
"implicit" components that need copying as well.  Finally,
somebody has to do the constraint check when the left-hand
side is *not* unconstrained, handle the case of
self-assignment, handle the case of slice assignments
(deciding between left-to-right or right-to-left based
on relative start addresses) and there are issues of
abort deferral, etc.

Despite all the above "moaning and groaning," it still
might be useful to allow user-defined assignment, even if
it is only used in certain cases (e.g. LHS exists, and
is initialized, and will still exist after the assignment).
Presumably the user-defined assignment would take over
the constraint check, and perhaps the check for self-assignment.
I suppose it might be nice for the compiler to generate the
check for self-assignment, since it is needed at most
once for an assignment statement (it is not needed on
each component), and it will often be possible to optimize
it away.  In most cases, the user-defined assignment would
just be an optimization.  However, because it would take
over the constraint check, the user-defined assignment
could also take on the job of implicit subtype conversion
if desired.  E.g., if you have a discriminated type like:

   type Text(Max : Natural) is record
       Data : String(1..Max);
   end record;

a user-defined assignment routine could automatically
pad or chop on assignment, rather than just complaining
about mismatched discriminants.

One final advantage of the Ada 95 approach has to do
with maintenance.  If the user provides the assignment
operation, then presumably they have to individually
assign each of the components.  If a new component is
added, there is no automatic handling of the new component,
and it might be forgotten in the user-defined assignment
operation.  By contrast, with the finalize/adjust approach,
the finalize for a record type doesn't need to call the
finalize operation for each component -- that happens
automatically.  The user-defined finalize for a record
type only needs to worry about finalizations over and
above those required for the individual components.
Ditto for adjust.  

I suppose for user-defined assignment, one could provide 
some way to get access to the underlying predefined
assignment operation (which omits calls on finalize/adjust 
for the record type), so that one could use that to handle
copying all the components, before or after some special
work is done at the record level.  E.g., one might save
the value of some component of the LHS, then do the
predefined assignment of the RHS into the LHS, and then
do a deep copy of the new value of the component potentially
reusing space allocated for the saved component value.
This would presumably be more efficient than doing the
finalize and adjust, which by necessity need to operate
independently of one another.


> 
> There's a reason that C++ has several types of constructors and in
> many ways the Ada mechanism is simpler.

Also, C++ doesn't have discriminants, at least not
explicitly (users sometimes define structs with
an array at the end that can be extended), so the
problem of "composing" a struct assignment out of the
assignment for the individual components is not
as difficult for the compiler.

> 
> --
> Mark Biggar
> mark.biggar@trustedsyslabs.com

-Tucker Taft
-- 
-Tucker Taft   stt@averstar.com   http://www.averstar.com/~stt/
Technical Director, Commercial Division, AverStar (formerly Intermetrics)
(http://www.averstar.com/services/IT_consulting.html)  Burlington, MA  USA



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-25  0:00           ` Marin David Condic
  2000-10-25  0:00             ` dmitry6243
@ 2000-10-27  7:12             ` Ray Blaak
  1 sibling, 0 replies; 35+ messages in thread
From: Ray Blaak @ 2000-10-27  7:12 UTC (permalink / raw)


Marin David Condic <mcondic.nospam@acm.org> writes:
> Ray Blaak wrote:
> > I really would like to be able to do:
> >
> >   procedure ":="(target : in out T; source : in T);

> there are a lot of obvious problems with trying to redefine
> ":=". The biggest problem is that it is not a subprogram - it is a primitive
> feature of the language.  I believe this might be an example of Godel's
> Theorem. There are some features of the language (any language) that cannot
> be expressed in the language itself. As a "function" it would require that a)
> the left parameter be treated as "out" and b) that the function need not
> return a result. (or that it could be ignored. Does a statement like: "X < Y
> ;" make sense in Ada?) As a procedure, you'd have to allow procedures to have
> symbol names - which opens up a whole can of worms. Further, it would mean
> allowing "infix procedures" which is hard to make sense of - or at least
> could make programs look really strange.

I don't think syntax issues would be a major problem here. It can't be a
function, since a return value makes no sense -- we need to operate on the
target directly. So yes, we would introduce procedures to have (the single
possible) "operator" name.

It is not really a Godel limitation. The problem is that Ada is missing the
necessary expressive power, likely on purpose in this case. The existence of
user-defined assignment in C++ indicates that it is quite doable in theory,
though, so it is only a matter of deciding how to extend Ada, if at all.

But this is a minor change as far as the Ada grammar goes. As for wierd infix
procedures, it would look quite normal: 

  a := b;

The wierd thing would be to see:

  ":="(a, b);

But that is not complicated from a parsing point of view. 

Still, parsing problems can be avoided by having a type's assigner be
accessible from T'Assign, and then allowing:

  procedure DeepCopy(target : in out T; source : in T);
  for T'Assign use DeepCopy;

One problem I can think of is that we need to access the primitive assignment
in order to implement the user-defined assignment. How does one refer to it?
There is no "super" keyword in Ada. I suppose various renaming tricks are
possible, but since they would always have to be done, that would quickly prove
tedious.

Perhaps we could have T'PrimitiveAssign be available for this purpose.

However, I am looking for the subtle stuff. So far I have heard:

a) discriminants problems involving the creation of fields when a different
  discriminat is specified

  - This one I would like to understand better. Why wouldn't something like
    this work:

    -- For all types T, T'Assign is the primitive ":=" operation.

    procedure ":="(target : in out T; source : in T) is
    begin
      -- do the usual thing:
      T'Assign(target, source); 
      -- now the extra work for doing deep copy, etc.
    end ":=";

b) User-defined assignment is not enough, also consider initialization and
  parameter passing.

  - Maybe so. So let's generalize these too.

> I'm sure there are dozens of other reasons why it was decided not to provide
> a means of letting the user define assignment. I'd think it would require
> perverting, warping and twisting language concepts too much. (Look at the
> semantics of C++ construction/destruction sometime - especially as it applies
> to function parameters - and see what an abomination that can become!

I don't have the sense that it warps things too much. C++ construction and user
assignment seems quite understandable, at least for the usual cases.

Are there any online archives somewhere that consider the issue? I think the
Ada 9X discussions used to be, but they seem to have disappeared.

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
blaak@infomatch.com                            The Rhythm has my soul.



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-26 13:25                   ` Robert A Duff
@ 2000-10-27  8:10                     ` dmitry6243
  0 siblings, 0 replies; 35+ messages in thread
From: dmitry6243 @ 2000-10-27  8:10 UTC (permalink / raw)


In article <wccwvevbuph.fsf@world.std.com>,
  Robert A Duff <bobduff@world.std.com> wrote:
> dmitry6243@my-deja.com writes:
>
> > There are lot of pitfalls here, but Initialize-Adjust-Finalize is
> > neither free of them. I had got a very nasty bug when a controlled
type
> > was passed by copy instead of by reference as I thought (or better
to
> > say, didn't care).
>
> Controlled types are always passed by reference.

Sorry. I should be more precise. Actually a non-controlled record was
passed by copy.

I don't remember all details now. It was an attempt to implement sets,
so that assingment would copy reference and increment use-count. It was
really tricky.

--
Regards,
Dmitry Kazakov


Sent via Deja.com http://www.deja.com/
Before you buy.



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-26 17:55                   ` tmoran
@ 2000-10-27  8:10                     ` dmitry6243
  0 siblings, 0 replies; 35+ messages in thread
From: dmitry6243 @ 2000-10-27  8:10 UTC (permalink / raw)


In article <Je_J5.358392$i5.5719531@news1.frmt1.sfba.home.com>,
  tmoran@bix.com wrote:
> >X : String (80);
> >X : MyType (Y, Z, 3.1415);
>  You can't do
> X : String (3.1415);
>  but you can do
> X : MyType (Y, Z, 3);
>

Using discriminants? What if MyType has no discriminants?

--
Regards,
Dmitry Kazakov


Sent via Deja.com http://www.deja.com/
Before you buy.



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-26 21:31                 ` Tucker Taft
@ 2000-10-27  8:46                   ` dmitry6243
  0 siblings, 0 replies; 35+ messages in thread
From: dmitry6243 @ 2000-10-27  8:46 UTC (permalink / raw)


In article <39F8A2CB.CA319F5@averstar.com>,
  Tucker Taft <stt@averstar.com> wrote:
> mark.biggar@trustedsyslabs.com wrote:
> > ...
> >
> > One of the problems with this proposal (redefineing ":=") is that
> > you would have to define Initialize, Adjust and Finialize anyway
> > as you need them to implement value parameter passing, temporary
> > creation and function return values correctly.  Each of those is
> > like assingment, but not exactly the same being, built out of the
> > three primitives in different ways.  So it makes more sense to just
> > define the three primitives and have the compiler generate
> > standard usage sequences then to redefine ":=" and have strange
> > and hard to understand things happen.
>
> This is part of the reason we did not allow the user
> to directly define ":=".  Another important reason has to
> do with assignment of composite objects (e.g. records
> and arrays) containing objects with user-defined
> assignment.  One desirable feature is that the assignment
> for a record, for example, is defined in terms of the
> assignment of its individual components.  Unfortunately,
> there are cases of record assignment in Ada where
> the left-hand-side doesn't contain a component that
> the right-hand-side does.  This happens if the left-hand-side
> is an unconstrained record with discriminants, and the
> right-hand-side happens to have different values for the
> discriminants than the values of the left-hand-side.
> As a result of the assignment, some components of the
> left-hand-side may disappear, and some may come into existence.
>
> For example:
>
>     type Rec(B : Boolean := False) is record
>         X : Cool_Controlled_Type;
>         case B is
>             when True =>
>                Y : Fancy_Controlled_Type;
>             when False =>
>                Z : Another_Controlled_Type;
>         end case;
>     end record;
>
>     R1 : Rec;  -- Defaults to B => False
>     R2 : Rec(B => True);
>
>      ...
>
>     R1 := R2;  -- R1.Z disappears, R1.Y is created,
>                --  R1.X overwritten
>
> It would be tricky at best to define how or whether
> user-defined ":=" for Cool_, Fancy_, and Another_Controlled_Type
> should be used in the above case.

[...]

I think that an assumption that Adjust should be generated from
user-defined ":=" is wrong, or at least very hard to implement.

IMO, used-defined ":=" should have no special semantic. It is not an
alternative to the copy constructor (= copy + Adjust).

The single link between them is that the default ":=" is generated as
Finalize, copy, Adjust.

In the given example, the compiler should simply ignore ":=" defined for
the types of Rec's components.

Another question is, whether copy constructor should be splitted into
block-copy and Adjust.

--
Regards,
Dmitry Kazakov


Sent via Deja.com http://www.deja.com/
Before you buy.



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-24  0:00         ` Ray Blaak
  2000-10-25  0:00           ` Marin David Condic
  2000-10-25  0:00           ` Francois Godme
@ 2000-10-27 18:11           ` Francois Godme
  2000-10-30 11:36             ` Robert A Duff
  2 siblings, 1 reply; 35+ messages in thread
From: Francois Godme @ 2000-10-27 18:11 UTC (permalink / raw)


Ray Blaak a �crit :

> Francois Godme <fgodme@bigfoot.com> writes:
>
> > I. Non-primitive procedures used as constructors of limited instances: As
> > limited instances can't be initialized with record aggregates, it is possible
> > to write code which forgets to initialize all record fields.
>
> Forgetting to initialize a field is equivalent to using a default constructor,
> no? In that case the Initialize routine can cover it.
>

Recall that the context was that defaulted record fields and the Initialize
routine were said inadequate to initialize all instances.

Take for example, the class Person. There are no such things as a default birth
date, a default sex or a default eyes color for instances of the class Person. To
provide methods to later fix the birth date, the sex and the eyes color to
appropriate values opens up instances to mistakes. These three instance attributes
should be constant and hence initialized by the constructor.





^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
@ 2000-10-29 22:51 rwilson007007
  2000-10-30  4:03 ` Ray Blaak
  2000-10-30 12:13 ` Marin David Condic
  0 siblings, 2 replies; 35+ messages in thread
From: rwilson007007 @ 2000-10-29 22:51 UTC (permalink / raw)


Greetings,

One thing that has struck me (vis-a-vis C++ versus Ada classes) is
that, unlike in Ada, the data structure associated with a C++ class is
never explicitly
defined by the language -
that is, afaik, the compiler can choose whatever underlying
represenation for the class it wishes.

If I desired to mimic the C++ notion of classes in Ada, I
would be tempted to encapsulate a tagged record instance within a
generic package
(the formal parameters of which act as constructor arguments and the
elaboration of which acts as a constructor). This both hides the
ada-record data representation and renders the familiar C++
"object_ref.method_name" style of method invocation syntax.

That is, rather than being tempted to overload Ada's assignment
operator, I would prefer to replace:
   "My_Object = new My_Class_Name (Argument_List)" in C++
with
   "package My_Object is new My_Class_Name.Instance (Argument_List)"
in Ada (see example below...).

** Could one of the wise participants in this discussion please
instruct me as to whether or not there is some fundamental problem or
limitation with Ada generics that makes this an unsensible approach?**

--Richard Wilson

-- BRIEF EXAMPLE:
-- SPEC
-- definition of class which inherits from a controlled object
with Some_Base_Class; -- limited controlled
with Attribute_1_Class;
with Attribute_2_Class;
with Attribute_3_Class;

package Some_Class is

   type Object is new Some_Base_Class.Object with
    record
      Attribute_1 : Attribute_1_Class.Object;
      Attribute_2 : Attribute_2_Class.Object;
      Attribute_3 : Attribute_3_Class.Object;
    end record;

   type Ref is access all Object'Class;

   procedure Method_1 (This : Ref; Parameter_1 : in Integer);
   procedure Method_2 (This : Ref; Returns : out
Attribute_1_Class.Object);

   generic
     Attribute_1 : Attribute_1_Class.Object :=
Attribute_1_Class.Default;
     Attribute_2 : Attribute_2_Class.Object;
     Attribute_3 : Attribute_3_Class.Object;

   package Instance is

     procedure Method_1 (Parameter_1 : Integer);
     procedure Method_2 (Returns : out Attribute_1_Class.Object);
     -- note that "This : Ref" argument is not necessary at this scope

     function Copy return Ref; -- returns deep copy
     procedure Destroy;
     -- object is created when Instance first instantiated
     -- if Destroy has been invoked, the instance of Instance is still
     --   in scope,  and and one wishes to use the object again
     --   then one must invoke:
     procedure Resurrect
       (Attribute_1 : in Attribute_1_Class.Object :=
Attribute_1_Class.Default;
        Attribute_2 : in Attribute_2_Class.Object;
        Attribute_3 : in Attribute_3_Class.Object);

     end Instance;

 private
     procedure Initialize (This : in out Object);
     procedure Finalize (This : in out Object);

end Some_Class;

-- BODY

package body Some_Class is

   procedure Method_1 (This : Ref; Parameter_1 :in Integer) is
   begin
      This.Attribute_2.Ticks := This.Attribute_2.Ticks + Parameter_1;
   end Method_1;

   procedure Method_2 (This : Ref; Returns : out
Attribute_1_Class.Object) is
   begin
     return This.Attribute_2;
   end Method_2;

   package body Instance is
     This : aliased Object;

     procedure Method_1 (Parameter_1 : in Integer) is
     begin
       Some_Class.Method_1 (This => This, Parameter_1 => Parameter_1);
     end Method_1;

     -- etc...

   begin
     This := new Object;
     This.Attribute_1 := Attribute_1;
     This.Attribute_2 := Attribute_2;
     This.Attribute_3 := Attribute_3;
     -- and so on...

   end Instance;

end Some_Class;

-- CLIENT CODE EXAMPLE

declare
   Init_Param_0 : Attribute_2_Class.Object := (Ticks => 23, others =>
0);
   Init_Param_1 : Attribute_3_Class.Object := (others => '');
   My_Copy : Some_Class.Ref;

  -- construct my object
  package My_Object is new Some_Class.Instance (Attribute_2 =>
Init_Param_0, Attribute_3 => Init_Param_1);

begin
   My_Object.Method_1 (Parameter_1 => 0);
   My_Object.Method_2 (Returns => Init_Param_0);
   My_Copy := My_Object.Copy_To;
   Some_Class.Method_1 (This => My_Copy, Parameter_1 => 0);
   My_Object.Destroy;
   My_Object.Reconstruct (Attribute_2 => Init_Param_0, Attribute_3 =>
Init_Param_1);
   My_Object.Copy (From => My_Copy);

end;


Sent via Deja.com http://www.deja.com/
Before you buy.



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-29 22:51 rwilson007007
@ 2000-10-30  4:03 ` Ray Blaak
  2000-10-30 12:13 ` Marin David Condic
  1 sibling, 0 replies; 35+ messages in thread
From: Ray Blaak @ 2000-10-30  4:03 UTC (permalink / raw)


rwilson007007@my-deja.com writes:

> If I desired to mimic the C++ notion of classes in Ada, I would be tempted
> to encapsulate a tagged record instance within a generic package
[...]
> That is, rather than being tempted to overload Ada's assignment
> operator, I would prefer to replace:
>    "My_Object = new My_Class_Name (Argument_List)" in C++
> with
>    "package My_Object is new My_Class_Name.Instance (Argument_List)"
> in Ada (see example below...).

The main problem with this approach is that packages are not first class
objects in Ada. They do not have addresses, cannot be passed as parameters or
compared to each other, etc.

Packages are static namespaces.

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
blaak@infomatch.com                            The Rhythm has my soul.



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-27 18:11           ` Francois Godme
@ 2000-10-30 11:36             ` Robert A Duff
  2000-10-30 22:03               ` dale
  0 siblings, 1 reply; 35+ messages in thread
From: Robert A Duff @ 2000-10-30 11:36 UTC (permalink / raw)


Francois Godme <fgodme@bigfoot.com> writes:

> Take for example, the class Person. There are no such things as a
> default birth date, a default sex or a default eyes color for
> instances of the class Person. To provide methods to later fix the
> birth date, the sex and the eyes color to appropriate values opens up
> instances to mistakes. These three instance attributes should be
> constant and hence initialized by the constructor.

You can use "(<>)" as the discriminant part to prevent default
initialization.  Then initialize the thing with a function call.
(But as you or somebody pointed out, this unfortunately does not
work for limited types.)

- Bob



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-29 22:51 rwilson007007
  2000-10-30  4:03 ` Ray Blaak
@ 2000-10-30 12:13 ` Marin David Condic
  2000-10-30 16:39   ` Randy Brukardt
  1 sibling, 1 reply; 35+ messages in thread
From: Marin David Condic @ 2000-10-30 12:13 UTC (permalink / raw)
  To: rwilson007007

rwilson007007@my-deja.com wrote:

> That is, rather than being tempted to overload Ada's assignment
> operator, I would prefer to replace:
>    "My_Object = new My_Class_Name (Argument_List)" in C++
> with
>    "package My_Object is new My_Class_Name.Instance (Argument_List)"
> in Ada (see example below...).
>
> ** Could one of the wise participants in this discussion please
> instruct me as to whether or not there is some fundamental problem or
> limitation with Ada generics that makes this an unsensible approach?**

Very clever! However, at least one issue would be raised. A generic
instanciation of My_Class_Name would result in a duplication of the object
code associated with My_Class_Name for every object of that class you
declare. This is at least true of every Ada compiler of which I am aware.
I don't know if anybody supports code sharing for generics on a currently
marketed Ada95 compiler. This technique could thus prove to be expensive
for classes where lots of objects are declared. Also, there could be some
time penalty in runtime instanciation that may be significant for classes
with lots of objects associated with them.

MDC
--
======================================================================
Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/
Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m
Visit my web site at:  http://www.mcondic.com/

    "Giving money and power to Government is like giving whiskey
    and car keys to teenage boys."

        --   P. J. O'Rourke
======================================================================





^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-30 12:13 ` Marin David Condic
@ 2000-10-30 16:39   ` Randy Brukardt
  0 siblings, 0 replies; 35+ messages in thread
From: Randy Brukardt @ 2000-10-30 16:39 UTC (permalink / raw)



Marin David Condic wrote in message <39FD65FB.388A05D0@acm.org>...
>rwilson007007@my-deja.com wrote:
>
>Very clever! However, at least one issue would be raised. A generic
>instanciation of My_Class_Name would result in a duplication of the
object
>code associated with My_Class_Name for every object of that class you
>declare. This is at least true of every Ada compiler of which I am
aware.
>I don't know if anybody supports code sharing for generics on a
currently
>marketed Ada95 compiler.

Janus/Ada 95 still uses "universal" code sharing for generics. There is
only one copy of the code for each generic unit; the instantiation
provides parameters.

I believe that there are other compilers that allow partial sharing in
limited instances.

Truth in advertising dept.: Janus/Ada 95 is not a complete
implementation of Ada 95 (a few parts are missing; notably to this
discussion, generic formal derived types). I don't know if there are any
reasons why our implementation cannot implement those part not yet
implemented (haven't found any yet, but...) I am a primary author of
that compiler, and still owrk at rrsoftware. (Our web site is
www.rrsoftware.com, if you care).

            Randy Brukardt.






^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Constructors/Destructors in Ada95
  2000-10-30 11:36             ` Robert A Duff
@ 2000-10-30 22:03               ` dale
  0 siblings, 0 replies; 35+ messages in thread
From: dale @ 2000-10-30 22:03 UTC (permalink / raw)


Robert A Duff wrote:

> You can use "(<>)" as the discriminant part to prevent default
> initialization.  Then initialize the thing with a function call.
> (But as you or somebody pointed out, this unfortunately does not
> work for limited types.)


I think it also looks very ugly, and is certainly non intuitive.
For a language that is based on the maxim of "maximum readability"
i think it fails badly here.


Dale



^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2000-10-30 22:03 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-10-18  0:00 Constructors/Destructors in Ada95 Francois Godme
2000-10-19  0:00 ` Marin David Condic
2000-10-19  0:00 ` Ted Dennison
2000-10-19  0:00 ` tmoran
2000-10-19  0:00   ` Francois Godme
2000-10-19  0:00     ` Ted Dennison
2000-10-20  0:00     ` Tucker Taft
2000-10-20  0:00       ` Francois Godme
2000-10-21  0:00         ` Marin David Condic
2000-10-23  0:00       ` Francois Godme
2000-10-24  0:00         ` Ray Blaak
2000-10-25  0:00           ` Marin David Condic
2000-10-25  0:00             ` dmitry6243
2000-10-25  0:00               ` mark.biggar
2000-10-26 11:44                 ` dmitry6243
2000-10-26 13:25                   ` Robert A Duff
2000-10-27  8:10                     ` dmitry6243
2000-10-26 17:55                   ` tmoran
2000-10-27  8:10                     ` dmitry6243
2000-10-26 21:31                 ` Tucker Taft
2000-10-27  8:46                   ` dmitry6243
2000-10-25  0:00               ` Pascal Obry
2000-10-26  0:00                 ` dmitry6243
2000-10-27  7:12             ` Ray Blaak
2000-10-25  0:00           ` Francois Godme
2000-10-27 18:11           ` Francois Godme
2000-10-30 11:36             ` Robert A Duff
2000-10-30 22:03               ` dale
2000-10-22  0:00     ` rwilson007007
2000-10-22  0:00       ` Francois Godme
2000-10-24  0:00         ` rwilson007007
  -- strict thread matches above, loose matches on Subject: below --
2000-10-29 22:51 rwilson007007
2000-10-30  4:03 ` Ray Blaak
2000-10-30 12:13 ` Marin David Condic
2000-10-30 16:39   ` Randy Brukardt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox