comp.lang.ada
 help / color / mirror / Atom feed
* Question about OO programming in Ada
@ 2003-11-25 19:04 Ekkehard Morgenstern
  2003-11-25 20:17 ` Randy Brukardt
                   ` (3 more replies)
  0 siblings, 4 replies; 109+ messages in thread
From: Ekkehard Morgenstern @ 2003-11-25 19:04 UTC (permalink / raw)



Hi guys,

I have a question about object-oriented programming in Ada:

Do I have to use class-wide types for object-oriented programming, or could
I use regular access types?

Like, when I declare a procedure

    procedure A ( B: in access all T'Class )

could I use a different method and still get all the benefits of Ada
object-oriented programming?

Like, what about:

    procedure A ( B: in access all T )

or

    procedure A ( B: in out T )

or

    procedure A ( B: in T )

Also, if I use access types, should I create new types or declare them
directly in the procedure/function, and what about the 'all' access
qualifier, should I create two types of access types (one with 'access' and
one with 'access all'), or should I declare them directly in the procedure
and decide individually what kind of access I need?

I would like to program as cleanly as possible in Ada right from the start,
so I'd be glad if someone could give me some hints. :-)






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

* Re: Question about OO programming in Ada
  2003-11-25 19:04 Question about OO programming in Ada Ekkehard Morgenstern
@ 2003-11-25 20:17 ` Randy Brukardt
  2003-11-26  0:34   ` Ekkehard Morgenstern
  2003-11-26  8:56   ` Peter Hermann
  2003-11-25 20:55 ` Martin Krischik
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 109+ messages in thread
From: Randy Brukardt @ 2003-11-25 20:17 UTC (permalink / raw)


"Ekkehard Morgenstern" <ekkehard.morgenstern@onlinehome.de> wrote in message
news:bq092s$9ph$1@online.de...
> Hi guys,
>
> I have a question about object-oriented programming in Ada:
>
> Do I have to use class-wide types for object-oriented programming, or
could
> I use regular access types?
>
> Like, when I declare a procedure
>
>     procedure A ( B: in access all T'Class )
>
> could I use a different method and still get all the benefits of Ada
> object-oriented programming?

Yikes! The "in" isn't allowed here, nor is the "all" -- they're both
assumed.

Second, you are generally best off avoiding access types when you can. That
certainly is true of O-O programming as well. Use access types for dynamic
structures; don't use them otherwise.

    procedure A (B : in out T'Class);

works just as well and doesn't have explicit access types.

When we designed Claw (a thick O-O interface for Windows), we avoided use of
access types in the interface in almost all cases. There are a lot of access
types in the implementation, but the user of Claw doesn't need to worry
about that. That's especially useful for simple programs (for instance,
those that declare just a few windows), because Ada can do all of the
storage management.

Ada allows access types for O-O programming because of a desire to allow
people to translate existing O-O designs for C++ and Java directly into Ada.
I think that's generally a mistake -- Ada can do better than using explicit
pointers.

                 Randy Brukardt.






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

* Re: Question about OO programming in Ada
  2003-11-25 19:04 Question about OO programming in Ada Ekkehard Morgenstern
  2003-11-25 20:17 ` Randy Brukardt
@ 2003-11-25 20:55 ` Martin Krischik
  2003-11-26  0:22   ` Ekkehard Morgenstern
  2003-11-25 21:48 ` Stephen Leake
  2003-12-06  7:48 ` Chad Bremmon
  3 siblings, 1 reply; 109+ messages in thread
From: Martin Krischik @ 2003-11-25 20:55 UTC (permalink / raw)


Ekkehard Morgenstern wrote:

> 
> Hi guys,
> 
> I have a question about object-oriented programming in Ada:
> 
> Do I have to use class-wide types for object-oriented programming, or
> could I use regular access types?
> 
> Like, when I declare a procedure
> 
>     procedure A ( B: in access all T'Class )

I made this mistake as well when I started. For OO it should be only:

procedure A ( B: in out T )

Unlike C++ no access is needed in Ada. And a class wide Types make your
procedure non "virtual". Some Tutorials are quite bad about describing that
point.

> could I use a different method and still get all the benefits of Ada
> object-oriented programming?
> 
> Like, what about:
> 
>     procedure A ( B: in access all T )

Should be:

procedure A ( B: access T )

and is Ok.
 
> or
> 
>     procedure A ( B: in out T )

Much better then using an acces type. 
 
> or
> 
>     procedure A ( B: in T )

Is like using "const&" in C++.

> Also, if I use access types, should I create new types or declare them
> directly in the procedure/function, and what about the 'all' access
> qualifier, should I create two types of access types (one with 'access'
> and one with 'access all'), or should I declare them directly in the
> procedure and decide individually what kind of access I need?

In Ada access type are not as often needed as in C++. So don't use then
unless you need them. References are done automatily by Ada.

If you know C++ then you will know about:

virtual void A (T& B); or virtual void A (T B);

As I said Ada will make the '&' Reference automaticly.

The "all" part is needed access to an object which have not been created
with "new". Using "all" for an access might reduce performace since the
compiler might have to do some extra checking on the access. Avoid if not
needed.

> I would like to program as cleanly as possible in Ada right from the
> start, so I'd be glad if someone could give me some hints. :-)

Hope I was of help.

You might also browse my Web page http://adacl.sourceforge.net. There are
lots of sources you can browse right on the web without downloading them.

With Regards.

-- 
mailto://krischik@users.sourceforge.net
http://adacl.sourceforge.net




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

* Re: Question about OO programming in Ada
  2003-11-25 19:04 Question about OO programming in Ada Ekkehard Morgenstern
  2003-11-25 20:17 ` Randy Brukardt
  2003-11-25 20:55 ` Martin Krischik
@ 2003-11-25 21:48 ` Stephen Leake
  2003-11-26  0:01   ` Ekkehard Morgenstern
  2003-12-06  7:48 ` Chad Bremmon
  3 siblings, 1 reply; 109+ messages in thread
From: Stephen Leake @ 2003-11-25 21:48 UTC (permalink / raw)


"Ekkehard Morgenstern" <ekkehard.morgenstern@onlinehome.de> writes:

> Hi guys,
> 
> I have a question about object-oriented programming in Ada:
> 
> Do I have to use class-wide types for object-oriented programming, or could
> I use regular access types?

Hmm. This very much depends on exactly what you mean by
"object-oriented". 

If you mean getting run-time dynamic dispatching, then somewhere in
your system you need a class-wide type (not everywhere). You also need
derived types with primitive operations. If these terms don't make
sense, please read an Ada book, such as "Ada as a Second Language" by
Norm Cohen; that will teach you what you need to know much more
quickly than asking here.

Or, try to explain here what you mean by "object-oriented". Use either
C++ or Ada terms, but try to be very explicit. Then we can tell you
how to do that correctly in Ada.

You have several very basic misunderstandings; reading a good Ada book
would probably be a good idea.

-- 
-- Stephe



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

* Re: Question about OO programming in Ada
  2003-11-25 21:48 ` Stephen Leake
@ 2003-11-26  0:01   ` Ekkehard Morgenstern
  2003-11-26  1:16     ` Jeffrey Carter
                       ` (3 more replies)
  0 siblings, 4 replies; 109+ messages in thread
From: Ekkehard Morgenstern @ 2003-11-26  0:01 UTC (permalink / raw)



"Stephen Leake" <Stephe.Leake@nasa.gov> schrieb im Newsbeitrag
news:uhe0sqfud.fsf@nasa.gov...
>
> > Do I have to use class-wide types for object-oriented programming, or
could
> > I use regular access types?
>
> Hmm. This very much depends on exactly what you mean by
> "object-oriented".

Ok. What I'd like to know is if I can view Ada record types as classes of
objects.

I.e. if I declare a record, like

        type My_Type1 is
        record
        Field1 : Integer;
        Field2:  Integer;
        end record;

Can I extend the record type like

        type My_Type2 is new My_Type with
        record
        Field3 : Integer;
        Field4 : Integer;
        end record;

such that the procedures declared to operate on type My_Type1 will operate
on the My_Type1 fields of My_Type2.

I gathered from what I read that I need to declare My_Type1 as a tagged
type.

Now, I read that method dispatching (with static dispatching corresponding
to method overloading in C++, and runtime dispatching corresponding to
virtual methods in C++), would be possible only by using a class-wide type,
such as My_Type1'Class in the first parameter of a procedure or in the
return value of a function.

First of all, how do I accomplish returning a reference in Ada? What is the
default behaviour of parameter passing and return in Ada? Someone said here
that if I use an "in" parameter in a procedure or function definition, the
object will be passed by reference. What about the returing of objects? Are
they returned by copy or returned by reference?

If I use a class-wide type, like My_Type1'Class, what kind of object is
that? Is it similar to Java's "object.class"?

What's the difference between passing a class-wide type as an in/out
parameter of a procedure, and passing an access to it?

i.e. the difference between

    procedure Proc( Param : in out Type'Class );

and

    type Type_Class_Access is access Type'Class;
    procedure Proc( Param : in Type_Class_Access );


> If you mean getting run-time dynamic dispatching, then somewhere in
> your system you need a class-wide type (not everywhere). You also need
> derived types with primitive operations. If these terms don't make
> sense, please read an Ada book, such as "Ada as a Second Language" by
> Norm Cohen; that will teach you what you need to know much more
> quickly than asking here.

I ordered myself a book about Ada already, "Programming in Ada 95" by John
Barnes, but it'll take a week or so till it arrives, so I'll have to make do
with other resources until then.

I think I know what run-time dynamic dispatching, class-wide types and
derived types refer to, but I'm not sure about implicit type conversions
that I can use.

For example, how do I get an access to an object in an expression?

Like, I have

    A : B ;
    C : access B;

how do I assign A to C? How can I get an access in mid-expression? Or is the
strong typing coming into effect that prevents assignment from one thing to
another?

Like, I'd want to do something similar like this:

    C := access A;

In C++, I can just write " C = &A" (if C is a pointer to B). How do I do
that in Ada?

I tried to use the pointer-like semantics of access to class-wide types, but
I ended up with doing manual type conversions (or casting) all over. Is that
normal?


> Or, try to explain here what you mean by "object-oriented". Use either
> C++ or Ada terms, but try to be very explicit. Then we can tell you
> how to do that correctly in Ada.

With object-oriented, I mean programming with classes of objects. Is that
explicit enough?

I would like to know how to handle methods of classes properly.

In the "Ada 95: Guide for C/C++ Programmers", the author used only access to
class-wide types, and some people here say that you don't really need them,
and I'd like to know why and how I could use the more implicit semantics of
parameter passing to get the same effect.

I thought by using this newsgroup, I could be spared from reading in the Ada
95 Rationale. Which is very explicit, but also verbose, and I'd like to make
my learning process quicker. ;-)

Also, some things aren't explained properly in the Rationale, because it
assumes the reader is familiar with Ada.

Like, I would like to know more about parameter passing, but I haven't yet
found the place where to look in the Rationale.  (ok I'm a bit too lazy
right now ;-) -- English is a foreign language to me, and I'd rather not
read umpteen pages of Ada language theory when I can avoid it! ;-) )


> You have several very basic misunderstandings; reading a good Ada book
> would probably be a good idea.

Might be that I have several misunderstandings.

I will read the Ada book when I receive it! :-)






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

* Re: Question about OO programming in Ada
  2003-11-25 20:55 ` Martin Krischik
@ 2003-11-26  0:22   ` Ekkehard Morgenstern
  2003-11-26  1:00     ` Jeffrey Carter
  2003-11-26 16:36     ` Martin Krischik
  0 siblings, 2 replies; 109+ messages in thread
From: Ekkehard Morgenstern @ 2003-11-26  0:22 UTC (permalink / raw)



"Martin Krischik" <krischik@users.sourceforge.net> schrieb im Newsbeitrag
news:21836716.smDW2dK3SM@linux1.krischik.com...
> Ekkehard Morgenstern wrote:
> > Do I have to use class-wide types for object-oriented programming, or
> > could I use regular access types?
> >
> > Like, when I declare a procedure
> >
> >     procedure A ( B: in access all T'Class )
>
> I made this mistake as well when I started. For OO it should be only:
>
> procedure A ( B: in out T )
>
> Unlike C++ no access is needed in Ada. And a class wide Types make your
> procedure non "virtual". Some Tutorials are quite bad about describing
that
> point.

Are you sure?

Should it not read at least

    procedure A ( B: in out T'Class )

Because when I inherit from a class I would like the methods of the base
class to work on the derived class as well.

Both the Ada Rationale and the Guide for C/C++ programmers say that you have
to declare the first parameter of a procedure or the return value of a
function to be of the class-wide type of the class to get the dynamic
runtime dispatching behaviour from Ada (like virtual functions in C++).

How would I have to declare them?

And how do I cast an object back to the reduced record type? And is that
necessary at all?

I guess I'll have to write some simple test cases.

> >     procedure A ( B: in access all T )
>
> Should be:
>
> procedure A ( B: access T )
>
> and is Ok.

The Ada 95 Reference says that the "all" attribute provides read-write
access to the object, while omitting it would only provide read-only access?
Or did I get that wrong?

(btw, I made short cuts with my examples, I know not all of the notation I
gave can be actually compiled)

> >     procedure A ( B: in out T )
>
> Much better then using an acces type.

But how about inheritance? Will the procedure operate on a type derived from
T?

> >     procedure A ( B: in T )
>
> Is like using "const&" in C++.

How about function returns? Can I return a reference to an object in the
same way?


> In Ada access type are not as often needed as in C++. So don't use then
> unless you need them. References are done automatily by Ada.
>
> If you know C++ then you will know about:
>
> virtual void A (T& B); or virtual void A (T B);
>
> As I said Ada will make the '&' Reference automaticly.

Does that help to avoid casting as well? And how do I return a reference
from a function? Or should I use procedures with in out parameters instead?


> The "all" part is needed access to an object which have not been created
> with "new".

You mean it doesn't give access to an object that was elaborated normally?

Now that explains some things.


> Using "all" for an access might reduce performace since the
> compiler might have to do some extra checking on the access. Avoid if not
> needed.

Ok.


> > I would like to program as cleanly as possible in Ada right from the
> > start, so I'd be glad if someone could give me some hints. :-)
>
> Hope I was of help.

Yes, thank you. :-)

> You might also browse my Web page http://adacl.sourceforge.net. There are
> lots of sources you can browse right on the web without downloading them.

Thanks, I have taken a look at it (not finished looking yet! ;-) ).





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

* Re: Question about OO programming in Ada
  2003-11-25 20:17 ` Randy Brukardt
@ 2003-11-26  0:34   ` Ekkehard Morgenstern
  2003-11-26  6:17     ` Vinzent 'Gadget' Hoefler
                       ` (2 more replies)
  2003-11-26  8:56   ` Peter Hermann
  1 sibling, 3 replies; 109+ messages in thread
From: Ekkehard Morgenstern @ 2003-11-26  0:34 UTC (permalink / raw)




"Randy Brukardt" <randy@rrsoftware.com> schrieb im Newsbeitrag
news:vs7eaf1kispja1@corp.supernews.com...
> "Ekkehard Morgenstern" <ekkehard.morgenstern@onlinehome.de> wrote in
message
>
> > Like, when I declare a procedure
> >
> >     procedure A ( B: in access all T'Class )
> >
> > could I use a different method and still get all the benefits of Ada
> > object-oriented programming?
>
> Yikes! The "in" isn't allowed here, nor is the "all" -- they're both
> assumed.

"in" is allowed, even if assumed. :-)

the "access all T'Class" part produces an error message with the compiler,
but I meant that to be exemplary anyway (to save me from typing an extra
"type" statement).


> Second, you are generally best off avoiding access types when you can.
That
> certainly is true of O-O programming as well. Use access types for dynamic
> structures; don't use them otherwise.
>
>     procedure A (B : in out T'Class);

How do I assign an object of type T to an access to T'Class?

Like, I have a node class,

    type Node;
    type Node_Ptr is access Node'Class;

    type Node is tagged
    record
        Succ : Node_Ptr;
        Pred : Node_Ptr;
    end record;

and a method like

    procedure NextNode( Node_Obj : in out Node'Class );

how do I assign a Node to a Node_Ptr?


> When we designed Claw (a thick O-O interface for Windows), we avoided use
of
> access types in the interface in almost all cases. There are a lot of
access
> types in the implementation, but the user of Claw doesn't need to worry
> about that. That's especially useful for simple programs (for instance,
> those that declare just a few windows), because Ada can do all of the
> storage management.

How can I exploit Ada's storage management to the max?

Especially when I have things like Lists and Nodes, Queues etc. or other
container classes?


> Ada allows access types for O-O programming because of a desire to allow
> people to translate existing O-O designs for C++ and Java directly into Ad
a.
> I think that's generally a mistake -- Ada can do better than using
explicit
> pointers.

How can I design it better? :-)

Do you know any good Ada programming style guides?

BTW, that Claw project of yours, is that a commercial product, or is it
free-/shareware? And where'd I get it from? :-)
(you can also e-mail me about the details, I'm curious to know! :-) -- I
might want to interface to Windows in Ada, I want to avoid using the
outdated Win32Ada, or are there newer versions?)






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

* Re: Question about OO programming in Ada
  2003-11-26  0:22   ` Ekkehard Morgenstern
@ 2003-11-26  1:00     ` Jeffrey Carter
  2003-11-26 16:36     ` Martin Krischik
  1 sibling, 0 replies; 109+ messages in thread
From: Jeffrey Carter @ 2003-11-26  1:00 UTC (permalink / raw)


Ekkehard Morgenstern wrote:

> Both the Ada Rationale and the Guide for C/C++ programmers say that
> you have to declare the first parameter of a procedure or the return
> value of a function to be of the class-wide type of the class to get
> the dynamic runtime dispatching behaviour from Ada (like virtual
> functions in C++).

Not at all. With a class-wide type, you get NO dispatching when you call 
the subprogram; you may get dispatching from calls made by the 
subprogram. To get dispatching, you need to call a parent type's 
operation with a value with a tag not known at compile time. Example:

package A is
    type Parent is tagged null record;

    procedure Op (P : in Parent); -- Op 1

     function Get return Parent'Class;
end A;

package A.B is
    type Child is new Parent with null record;

    procedure Op (P : in Child); -- Op 2
end A.B;
...
with A;
...
A.Op (P => A.Get); -- Dispatches to the correct Op

-- 
Jeff Carter
"Sheriff murdered, crops burned, stores looted,
people stampeded, and cattle raped."
Blazing Saddles
35




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

* Re: Question about OO programming in Ada
  2003-11-26  0:01   ` Ekkehard Morgenstern
@ 2003-11-26  1:16     ` Jeffrey Carter
  2003-11-26 15:10     ` Georg Bauhaus
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 109+ messages in thread
From: Jeffrey Carter @ 2003-11-26  1:16 UTC (permalink / raw)


Ekkehard Morgenstern wrote:

> First of all, how do I accomplish returning a reference in Ada? What
> is the default behaviour of parameter passing and return in Ada?
> Someone said here that if I use an "in" parameter in a procedure or
> function definition, the object will be passed by reference. What
> about the returing of objects? Are they returned by copy or returned
> by reference?

Parameter modes (in, in out, out) have NOTHING to do with parameter 
passing mechanisms. "In" means the subprogram cannot modify the 
parameter; "in out" that the caller provides a value and the subprogram 
modifies it; and "out" that the subprogram creates a value in the parameter.

Elementary types (scalars and access types) are always passed by copy, 
regardless of the parameter mode. Limited types and tagged types are 
always passed by reference, regardless of the parameter mode. Other 
types are passed by whichever method the compiler determines is best. 
For the gory details, see ARM 6.2.

Like many people from a C/++ background, you're thinking at much too low 
a level. As a beginner, you should not be using access types unless 
you're creating dynamic data structures. You should not be worrying 
about parameter passing mechanisms or how values are returned from a 
function. Ada takes care of this for you, and generally does a pretty 
good job. Unless you're doing hard real-time software, you probably 
don't need to worry about how good a job the compiler is doing.

> I will read the Ada book when I receive it! :-)

While you're waiting, I suggest you work through one or more of the
tutorials, and read one of the books, available online through
www.adapower.com or www.adaworld.com.

-- 
Jeff Carter
"Sheriff murdered, crops burned, stores looted,
people stampeded, and cattle raped."
Blazing Saddles
35




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

* Re: Question about OO programming in Ada
  2003-11-26  0:34   ` Ekkehard Morgenstern
@ 2003-11-26  6:17     ` Vinzent 'Gadget' Hoefler
  2003-11-26  9:29     ` Dmitry A. Kazakov
  2003-11-26 15:54     ` Stephen Leake
  2 siblings, 0 replies; 109+ messages in thread
From: Vinzent 'Gadget' Hoefler @ 2003-11-26  6:17 UTC (permalink / raw)


Ekkehard Morgenstern wrote:

>BTW, that Claw project of yours, is that a commercial product, or is it
>free-/shareware? And where'd I get it from? :-)

It is sort of both. ;)

<URL:http://www.rrsoftware.com/html/prodinf/claw/clawdemo.htm>


Vinzent.



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

* Re: Question about OO programming in Ada
  2003-11-25 20:17 ` Randy Brukardt
  2003-11-26  0:34   ` Ekkehard Morgenstern
@ 2003-11-26  8:56   ` Peter Hermann
  1 sibling, 0 replies; 109+ messages in thread
From: Peter Hermann @ 2003-11-26  8:56 UTC (permalink / raw)


Randy Brukardt <randy@rrsoftware.com> wrote:
> Ada allows access types for O-O programming because of a desire to allow
> people to translate existing O-O designs for C++ and Java directly into Ada.
> I think that's generally a mistake -- Ada can do better than using explicit
> pointers.

Moreover, access types are not SPARK compliant.
www.sparkada.com

-- 
--Peter Hermann(49)0711-685-3611 fax3758 ica2ph@csv.ica.uni-stuttgart.de
--Pfaffenwaldring 27 Raum 114, D-70569 Stuttgart Uni Computeranwendungen
--http://www.csv.ica.uni-stuttgart.de/homes/ph/
--Team Ada: "C'mon people let the world begin" (Paul McCartney)



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

* Re: Question about OO programming in Ada
  2003-11-26  0:34   ` Ekkehard Morgenstern
  2003-11-26  6:17     ` Vinzent 'Gadget' Hoefler
@ 2003-11-26  9:29     ` Dmitry A. Kazakov
  2003-11-26 15:54     ` Stephen Leake
  2 siblings, 0 replies; 109+ messages in thread
From: Dmitry A. Kazakov @ 2003-11-26  9:29 UTC (permalink / raw)


On Wed, 26 Nov 2003 01:34:04 +0100, "Ekkehard Morgenstern"
<ekkehard.morgenstern@onlinehome.de> wrote:

>How do I assign an object of type T to an access to T'Class?

Use 'Access and 'Unchecked_Access attributes to get a pointer (access
type object) to some existing [aliased!] object. Conversion from
specific to class-wide pointer is implicit. It is also true when you
use "new" to create a new object. The result is a specific pointer
which can be implicitly converted to a class-wide one.

>Like, I have a node class,
>
>    type Node;
>    type Node_Ptr is access Node'Class;
>
>    type Node is tagged
>    record
>        Succ : Node_Ptr;
>        Pred : Node_Ptr;
>    end record;
>
>and a method like
>
>    procedure NextNode( Node_Obj : in out Node'Class );
>
>how do I assign a Node to a Node_Ptr?

You can, but it is a bad design. Though "in out" means that you can
modify object, still it is not allowed to change the object's tag. So
if the next node has another specific type than one of Node_Obj you
will get Constraint_Error:

procedure Next_Node (Node_Obj : in out Node'Class) is
begin
   Node_Obj := Node_Obj.Succ.all;
     -- May raise Constraint_Error on many occasions!
end Next_Node;

So at least it should be:

function Next_Node (Node_Obj : in Node'Class) return Node'Class is
begin
   return Node_Obj.Succ.all;
      -- Also raises Constraint_Error,
      -- but only if Node_Obj.Succ is null
end Next_Node;

Then note that this function would copy the node. Very likely it is
not what you want. Probably, nodes cannot be copied at all so:

type Node is tagged limited record ...

This would prevent any attempt to assign a node. [You still may have
functions returning limited objects, their results cannot be assigned
but can be renamed.]

Even more, probably a node should remove itself from the graph upon
destruction. Then:

type Node is new Ada.Finalization.Limited_Controlled with record ...

Probably there should be no empty nodes, and thus:

type Node is abstract
   new Ada.Finalization.Limited_Controlled with record ...

Anyway the right thing likely is:

function Next_Node (Node_Obj : in Node'Class) return Node_Ptr is
begin
   return Node_Obj.Succ;
end Next_Node;

Note that Randy's point is still valid. Pointers are bad, though
inevitable on some lower levels of abstraction as we see it here.
Should you change the abstraction and switch from Get_Next to, say, an
node navigatior, which would call a dispatching procedure that does
something with a node ... you could get rid of pointers.

>How can I exploit Ada's storage management to the max?
>
>Especially when I have things like Lists and Nodes, Queues etc. or other
>container classes?

You can allocate items, nodes in your own storage pools. If you know
something special about the way items get allocated / deallocated, you
may implement a more efficient memory allocation strategy than the
default one. For example, in my project I have dynamically created /
removed constraints, about which I know that they are always allocated
in LIFO. I cannot use the program stack (declare-begin-end block) for
them. So I chose to implement a stack memory pool and use it to keep
the constraining objects there.

--
Regards,
Dmitry Kazakov
http://www.dmitry-kazakov.de



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

* Re: Question about OO programming in Ada
  2003-11-26  0:01   ` Ekkehard Morgenstern
  2003-11-26  1:16     ` Jeffrey Carter
@ 2003-11-26 15:10     ` Georg Bauhaus
  2003-11-26 15:48     ` Stephen Leake
  2003-11-26 17:58     ` Robert I. Eachus
  3 siblings, 0 replies; 109+ messages in thread
From: Georg Bauhaus @ 2003-11-26 15:10 UTC (permalink / raw)


Ekkehard Morgenstern <ekkehard.morgenstern@onlinehome.de> wrote:
: 
: I gathered from what I read that I need to declare My_Type1 as a tagged
: type.

Yes.
 
: Now, I read that method dispatching (with static dispatching corresponding
: to method overloading in C++, and runtime dispatching corresponding to
: virtual methods in C++), would be possible only by using a class-wide type,
: such as My_Type1'Class in the first parameter of a procedure or in the
: return value of a function.

Uhm, if you really have a need for runtime dispatching, not just
"virtual objects", that is. For example, if one Node needs to be
hooked onto another, where the other node is a Very_Specialised_Node
remotely derived from Node, they still both have the "hooking" operations
of Node. If they have the names a and vsa, respectively, then a call on
the hooking procedure declared as hook(n1, n2: in out Node) might look
like

   hook(a, Node(vsa));

vsa is then seen as a Node. (Not casted, just a view conversion)


Here is an example that demonstrates a few things, whether it is
well done or not I can't say.
It isn't complete but I'm sure you can add some functionality.


package Disp is

   type My_Type1 is
     tagged record
        Field1 : Integer := 100;
        Field2:  Integer := 42;
     end record;


   procedure op (item: in out My_Type1);
   function f1 (item: My_Type1) return Integer;

   type My_Type2 is new My_Type1 with
     record
        Field3 : Integer := -100;
        Field4:  Integer := 5_000_000;
     end record;

   procedure op (item: in out My_Type2);
   --  inherit f1

end Disp;


with Ada.Text_IO;   use Ada;

package body Disp is

   procedure op (item: in out My_Type1) is
   begin
      Text_IO.put_line("op enter for My_Type1");
      item := (Field1 => item.Field1 + 1,
               Field2 => item.Field2 - 42);

      Text_IO.put_line("op leave for My_Type1");
   end op;

   function f1 (item: My_Type1) return Integer is
   begin
      return item.Field1;
   end f1;



   procedure op (item: in out My_Type2) is
   begin
      Text_IO.put_line("op enter for My_Type2");

      --  view item as a My_Type1 object (conversion)
      --  and call the corresponding op:

      op(My_Type1(item));

      item.Field4 := 0;

      Text_IO.put_line("op leave for My_Type2");
   end op;

   --  inherit f1

end Disp;


with disp; use disp;

with Ada.Text_IO;  use Ada;

procedure disp_test is

   x1: aliased My_Type1;    -- aliased is here because of the pointers
   x2: aliased My_Type2;    -- I rarely need them

   type Any_Of_My_Type is access all My_Type1'Class;

   xc: Any_Of_My_Type;

   procedure choose(x: in out My_Type1'Class);
   --  calls an op depending on x's type

   procedure as_well(x: access My_Type1'Class);
   --  calls an op depending on x's designated type

   procedure choose(x: in out My_Type1'Class) is
   begin
      op(x);
   end choose;


   procedure as_well(x: access My_Type1'Class) is
   begin
      op(x.all);
   end as_well;

begin

   --  calls on operations of x1's and x2's types, resp

   Text_IO.put_line("x1's Field1: " & Integer'image(f1(x1)));
   Text_IO.put_line("x2's Field1: " & Integer'image(f1(x2)));

   op(x1);

   Text_IO.put_line("x1's Field1: " & Integer'image(f1(x1)));
   Text_IO.put_line("x2's Field1: " & Integer'image(f1(x2)));

   op(x2);

   Text_IO.put_line("x1's Field1: " & Integer'image(f1(x1)));
   Text_IO.put_line("x2's Field1: " & Integer'image(f1(x2)));


   --  xc will point to objects of type My_Type1 or My_Type2

   Text_IO.put_line("moving pointers");

   xc := x1'access;
   op(xc.all);

   Text_IO.put_line("x1's Field1: " & Integer'image(f1(x1)));
   Text_IO.put_line("x2's Field1: " & Integer'image(f1(x2)));

   xc := x2'access;
   op(xc.all);

   Text_IO.put_line("x1's Field1: " & Integer'image(f1(x1)));
   Text_IO.put_line("x2's Field1: " & Integer'image(f1(x2)));


   Text_IO.put_line("have the tag decide");

   choose(x1);
   choose(x2);
   choose(xc.all);

   Text_IO.put_line("have the tag decide, too");

   as_well(x1'access);
   as_well(x2'access);
   as_well(xc);

end disp_test;



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

* Re: Question about OO programming in Ada
  2003-11-26  0:01   ` Ekkehard Morgenstern
  2003-11-26  1:16     ` Jeffrey Carter
  2003-11-26 15:10     ` Georg Bauhaus
@ 2003-11-26 15:48     ` Stephen Leake
  2003-11-26 16:24       ` Hyman Rosen
  2003-11-26 17:58     ` Robert I. Eachus
  3 siblings, 1 reply; 109+ messages in thread
From: Stephen Leake @ 2003-11-26 15:48 UTC (permalink / raw)


"Ekkehard Morgenstern" <ekkehard.morgenstern@onlinehome.de> writes:

> "Stephen Leake" <Stephe.Leake@nasa.gov> schrieb im Newsbeitrag
> news:uhe0sqfud.fsf@nasa.gov...
> >
> > > Do I have to use class-wide types for object-oriented programming, or
> could
> > > I use regular access types?
> >
> > Hmm. This very much depends on exactly what you mean by
> > "object-oriented".
> 
> Ok. What I'd like to know is if I can view Ada record types as classes of
> objects.

Yes, that's what types are.

> I.e. if I declare a record, like
> 
>         type My_Type1 is
>         record
>         Field1 : Integer;
>         Field2:  Integer;
>         end record;
> 
> Can I extend the record type like
> 
>         type My_Type2 is new My_Type with
>         record
>         Field3 : Integer;
>         Field4 : Integer;
>         end record;
> 
> such that the procedures declared to operate on type My_Type1 will operate
> on the My_Type1 fields of My_Type2.

Ah. That's _not_ what "class" means, but yes, Ada can do this. It's
called "inheritance". You even got the syntax correct, except you need
"tagged" in My_Type1.

> I gathered from what I read that I need to declare My_Type1 as a
> tagged type.

Yes.

> Now, I read that method dispatching (with static dispatching
> corresponding to method overloading in C++, and runtime dispatching
> corresponding to virtual methods in C++), 

This isn't quite right. C++ does not have anything directly
corresponding to static dispatch. Method overloading in C++
corresponds to overloading in Ada.

> would be possible only by using a class-wide type, such as
> My_Type1'Class in the first parameter of a procedure or in the
> return value of a function.

No, but close. You need to pass a class-wide _object_ to a primitive
subprogram to get dispatching. Complete compilable example:

package Class_Wide_Aux is
   type My_Type1 is tagged record
      Field1 : Integer;
      Field2 : Integer;
   end record;

   procedure Foo (Item : in My_Type1);

   type My_Type2 is new My_Type1 with record
      Field3 : Integer;
      Field4 : Integer;
   end record;

   procedure Foo (Item : in My_Type2);

end Class_Wide_Aux;

with Ada.Text_IO;
package body Class_Wide_Aux is

   procedure Foo (Item : in My_Type1)
   is begin
      Ada.Text_Io.Put_Line ("Foo (My_Type1)" & Integer'Image (Item.Field1));
   end Foo;

   procedure Foo (Item : in My_Type2)
   is begin
      Ada.Text_Io.Put_Line ("Foo (My_Type2)" & Integer'Image (Item.Field3));
   end Foo;


end Class_Wide_Aux;

with Class_Wide_Aux; use Class_Wide_Aux;
procedure Class_Wide
is
   function Get_An_Object (From : in Integer) return My_Type1'Class
   is begin
      if From = 1 then
         return My_Type1'(1, 2);
      else
         return My_Type2'(1, 2, 3, 4);
      end if;
   end Get_An_Object;

   Class_Wide_Obj_1 : My_Type1'Class := Get_An_Object (1);
   Class_Wide_Obj_2 : My_Type1'Class := Get_An_Object (2);
begin
   Foo (Class_Wide_Obj_1);
   Foo (Class_Wide_Obj_2);
end Class_Wide;


The call to Foo will dispatch on the actual type of Class_Wide_Obj_*:

gnatmake class_wide
gcc -c -I./ -I.. -I- ..\class_wide.adb
gnatbind -aO./ -I.. -I- -x class_wide.ali
gnatlink class_wide.ali
./class_wide.exe 
Foo (My_Type1) 1
Foo (My_Type2) 3

> First of all, how do I accomplish returning a reference in Ada? 

Why is this "first"? There is nothing corresponding to a C++
"reference" in Ada; the closest thing is a constant access type.

Ah. In C++, the only way to get a class-wide object is with a pointer.
You can declare a class-wide pointer in Ada

type Class_Wide_Access_Type1 is access all My_Type1'Class;

but it is not necessary, as the example above shows. 

> What is the default behaviour of parameter passing and return in
> Ada? Someone said here that if I use an "in" parameter in a
> procedure or function definition, the object will be passed by
> reference. What about the returing of objects? Are they returned by
> copy or returned by reference?

Copy or reference is orthogonal to in/out/return; the compiler is free
to choose the best method for each subprogram. Except that tagged and
fully limited types are always by-reference, to avoid problems that I
can never quite remember :).

> If I use a class-wide type, like My_Type1'Class, what kind of object
> is that? Is it similar to Java's "object.class"?

Class_Wide_Obj_1 is an object of type My_Type1'Class, which is a
"class-wide type".

> What's the difference between passing a class-wide type as an in/out
> parameter of a procedure, and passing an access to it?

> i.e. the difference between
> 
>     procedure Proc( Param : in out Type'Class );

This is not dispatching. Proc should do something that is truly proper
for all derived types, or it should dispatch internally.

>     type Type_Class_Access is access Type'Class;
>     procedure Proc( Param : in Type_Class_Access );

This is not dispatching, but is class-wide.

To get dispatching when you need a pointer, use an access parameter:

procedure Foo (Item : access My_Type1);

However, you generally don't need pointers in Ada. Well, sometimes you
really do, but you should start by assuming you don't. There are many
things C++ needs pointers for that Ada doesn't.

> I think I know what run-time dynamic dispatching, class-wide types and
> derived types refer to, but I'm not sure about implicit type conversions
> that I can use.
> 
> For example, how do I get an access to an object in an expression?
> 
> Like, I have
> 

I'll assume:

type B is ...;
type B_Access is access all B'

>     A : B ;

This should be:

A : aliased B;

The compiler needs to know you will be using a pointer to A.

>     C : access B;

This should be :

C : B_Access;

> how do I assign A to C? 

they are of different types, so you can't. Perhaps you meant "how do I
make C point to A":

C := A'Access;

Note that there are "accessibility rules" that limit this; I'll leave
that for another time (read your book :).

> I tried to use the pointer-like semantics of access to class-wide types, but
> I ended up with doing manual type conversions (or casting) all over. Is that
> normal?

No. If you find yourself doing type conversions, you are doing
something wrong.

> > Or, try to explain here what you mean by "object-oriented". Use
> > either C++ or Ada terms, but try to be very explicit. Then we can
> > tell you how to do that correctly in Ada.
> 
> With object-oriented, I mean programming with classes of objects. Is that
> explicit enough?

Nope, sorry. Terms like "inheritance", "dynamic dispatch",
"polymorphism", "overriding", "information hiding", "abstract data
type", can all be part of "object-oriented", but are all very
different from each other.

Ada 83, and even C, support "classes of objects", but that's probably
not what you mean.

> In the "Ada 95: Guide for C/C++ Programmers", the author used only access to
> class-wide types, and some people here say that you don't really need them,
> and I'd like to know why and how I could use the more implicit semantics of
> parameter passing to get the same effect.

See the above example. That's a very bad thing for the book to do. It
is the closest match to the "C++ way", but a _good_ book would point
out how to do it better in Ada.

> I thought by using this newsgroup, I could be spared from reading in
> the Ada 95 Rationale. Which is very explicit, but also verbose, and
> I'd like to make my learning process quicker. ;-)

Well, yes, asking here is better than reading the Rationale. But a
book like Barnes or Cohen is a better place to start.

> Also, some things aren't explained properly in the Rationale,
> because it assumes the reader is familiar with Ada.

Yes; it's mainly for compiler implementers and language lawyers.

> English is a foreign language to me,
> and I'd rather not read umpteen pages of Ada language theory when I
> can avoid it! ;-) )

You English looks very good to me, but that does make it harder. See
www.adapower.com for reviews of other books you can get; I suspect you
will want "Ada as a Second Language"; it's the most language-lawyer
like, while still being more accessible than the Ada Rationale.

Welcome to the wonderful world of Ada; the only way to program :).

-- 
-- Stephe

PS. Thank you for dragging this newsgroup back to its roots;
explaining how to use Ada :).



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

* Re: Question about OO programming in Ada
  2003-11-26  0:34   ` Ekkehard Morgenstern
  2003-11-26  6:17     ` Vinzent 'Gadget' Hoefler
  2003-11-26  9:29     ` Dmitry A. Kazakov
@ 2003-11-26 15:54     ` Stephen Leake
  2003-11-26 20:07       ` Randy Brukardt
  2 siblings, 1 reply; 109+ messages in thread
From: Stephen Leake @ 2003-11-26 15:54 UTC (permalink / raw)


"Ekkehard Morgenstern" <ekkehard.morgenstern@onlinehome.de> writes:

> "Randy Brukardt" <randy@rrsoftware.com> schrieb im Newsbeitrag
> news:vs7eaf1kispja1@corp.supernews.com...
> > "Ekkehard Morgenstern" <ekkehard.morgenstern@onlinehome.de> wrote in
> message
> >
> > > Like, when I declare a procedure
> > >
> > >     procedure A ( B: in access all T'Class )
> > >
> > > could I use a different method and still get all the benefits of Ada
> > > object-oriented programming?
> >
> > Yikes! The "in" isn't allowed here, nor is the "all" -- they're both
> > assumed.
> 
> "in" is allowed, even if assumed. :-)

Hmm. Never make statements like this without first running the code
thru a compiler. Randy writes compilers and edits the Ada Language
Reference Manual (you probably did not know this), so he knows what
he's talking about.

"in" is neither assumed nor allowed.

> the "access all T'Class" part produces an error message with the
> compiler, 

Always believe the compiler! Well, I've never met a compiler that I
didn't find a bug in, but you should certainly start by assuming the
compiler is correct.

> but I meant that to be exemplary anyway (to save me from typing an
> extra "type" statement).

Ada, as you will discover, is _not_ for people who don't like typing
"type" statements. There's nothing "extra" about them!

-- 
-- Stephe



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

* Re: Question about OO programming in Ada
  2003-11-26 15:48     ` Stephen Leake
@ 2003-11-26 16:24       ` Hyman Rosen
  0 siblings, 0 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-11-26 16:24 UTC (permalink / raw)


Stephen Leake wrote:
> C++ does not have anything directly corresponding to static dispatch.

If class C contains method F, and object O is of a class derived from C,
then the call O.C::F() will invoke the method F defined in C, regardless
of whether F is virtual and overridden. Do you mean something else?




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

* Re: Question about OO programming in Ada
  2003-11-26  0:22   ` Ekkehard Morgenstern
  2003-11-26  1:00     ` Jeffrey Carter
@ 2003-11-26 16:36     ` Martin Krischik
  2003-11-26 18:09       ` Robert I. Eachus
  1 sibling, 1 reply; 109+ messages in thread
From: Martin Krischik @ 2003-11-26 16:36 UTC (permalink / raw)


Ekkehard Morgenstern wrote:

> 
> "Martin Krischik" <krischik@users.sourceforge.net> schrieb im Newsbeitrag
> news:21836716.smDW2dK3SM@linux1.krischik.com...
>> Ekkehard Morgenstern wrote:
>> > Do I have to use class-wide types for object-oriented programming, or
>> > could I use regular access types?
>> >
>> > Like, when I declare a procedure
>> >
>> >     procedure A ( B: in access all T'Class )
>>
>> I made this mistake as well when I started. For OO it should be only:
>>
>> procedure A ( B: in out T )
>>
>> Unlike C++ no access is needed in Ada. And a class wide Types make your
>> procedure non "virtual". Some Tutorials are quite bad about describing
> that
>> point.
> 
> Are you sure?
> 
> Should it not read at least
> 
>     procedure A ( B: in out T'Class )

No. I thought so as well in the beginning. But it is the other way round.
"virtual" aus standart in Ada - using T'Class makes it not "virtual"

> Because when I inherit from a class I would like the methods of the base
> class to work on the derived class as well.

Yes.

> Both the Ada Rationale and the Guide for C/C++ programmers say that you
> have to declare the first parameter of a procedure or the return value of
> a function to be of the class-wide type of the class to get the dynamic
> runtime dispatching behaviour from Ada (like virtual functions in C++).

When you call the function, not when you declare the funtion!

procedure A ( B: in out T);

I : T;
I_Class : T'Class := T'Class (I);

A (I_Class);

> And how do I cast an object back to the reduced record type? And is that
> necessary at all?

Best you you rename them:

I_Class : T'Class renames T'Class (I);

Of better detail look at procedure Analyze_GNU in
http://adacl.sourceforge.net/html/sarHTML-CommandLine__adb.htm
to see how dispaching calls (This_C) und calls to parent methods (This_S)
are done in Ada.

> The Ada 95 Reference says that the "all" attribute provides read-write
> access to the object, while omitting it would only provide read-only
> access? Or did I get that wrong?

no!

access is access to heap storage.
access all is access to heap, stack and other storage.
access constant is constant access.
 
> (btw, I made short cuts with my examples, I know not all of the notation I
> gave can be actually compiled)

No Problem.
 
>> >     procedure A ( B: in out T )
>>
>> Much better then using an acces type.
> 
> But how about inheritance? Will the procedure operate on a type derived
> from T?

Yes.

>> >     procedure A ( B: in T )
>>
>> Is like using "const&" in C++.
> 
> How about function returns? Can I return a reference to an object in the
> same way?

Again the Ada Compiler will use the most efficient way. 

>> In Ada access type are not as often needed as in C++. So don't use then
>> unless you need them. References are done automatily by Ada.
>>
>> If you know C++ then you will know about:
>>
>> virtual void A (T& B); or virtual void A (T B);
>>
>> As I said Ada will make the '&' Reference automaticly.
> 
> Does that help to avoid casting as well? And how do I return a reference
> from a function? Or should I use procedures with in out parameters
> instead?

Depends. You can return any non limited type with a function. Ada will will
use by reference or by value depends what is best. functions however can
only have in parameters. And you can not return a limited type. 

Use out parameter if functions won't work.

With Regards

Martin


-- 
mailto://krischik@users.sourceforge.net
http://adacl.sourceforge.net




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

* Re: Question about OO programming in Ada
  2003-11-26  0:01   ` Ekkehard Morgenstern
                       ` (2 preceding siblings ...)
  2003-11-26 15:48     ` Stephen Leake
@ 2003-11-26 17:58     ` Robert I. Eachus
  2003-11-27  2:10       ` Ekkehard Morgenstern
  3 siblings, 1 reply; 109+ messages in thread
From: Robert I. Eachus @ 2003-11-26 17:58 UTC (permalink / raw)


Ekkehard Morgenstern wrote:

> Ok. What I'd like to know is if I can view Ada record types as classes of
> objects.

Yes.  In Ada every type is a member of one or more classes of types. 
But for dispatching, read on.

> I.e. if I declare a record, like
> 
>         type My_Type1 is
>         record
>         Field1 : Integer;
>         Field2:  Integer;
>         end record;
> 
> Can I extend the record type like
> 
>         type My_Type2 is new My_Type with
>         record
>         Field3 : Integer;
>         Field4 : Integer;
>         end record;
> 
> such that the procedures declared to operate on type My_Type1 will operate
> on the My_Type1 fields of My_Type2.

To extend a record type, the parent type needs to be tagged.  Of course, 
the parent can be explicitly derived from a third tagged type, and so 
on.  The rule is that to be tagged, a non-derived type must include the 
reserved word tagged in its declaration, and a derived type must include 
a extension part, which may be null.

> I gathered from what I read that I need to declare My_Type1 as a tagged
> type.

See above.

> Now, I read that method dispatching (with static dispatching corresponding
> to method overloading in C++, and runtime dispatching corresponding to
> virtual methods in C++), would be possible only by using a class-wide type,
> such as My_Type1'Class in the first parameter of a procedure or in the
> return value of a function.

This may be correct for C++ but it is definitely not correct for Ada. 
In Ada, a primitive operation can be dispatched to if it has a parameter 
or return type that is a tagged type.  If there is more than one such 
parameter or result type, they must all resolve to the same specific 
type at the point of the call.  If you want to write a dispatching 
operation that takes more than one tagged operand, and of different 
specific types you have to select one such parameter as the one that you 
dispatch on.  The non-dispatching parameters or result type must be 
class wide.  Inside the operation you can further dispatch on the 
classwide arguments.

That is complex enough to deserve an example.  Let's say you want to 
write a registration system for your state's DMV.  For driver's 
licenses, you have an operand of type Person.  To allow for special 
processing in some cases, you decide to make this type tagged.  Since 
you don't want multiple copies of the same person in the system, let's 
make Person limited:

type Person is tagged limited private;

To deal with the complexities of registering truck, motorcycles, etc., 
you create a vehicle type:

type Vehicle is tagged limited private;

Of course, we need a registration type which will also have several 
variants, and you decide to make this type tagged as well:

type Registration is tagged limited private;

Since I made these limited, there will be a need for access types so 
that for example a registration can contain a vehicle reference and an 
owner reference:

type Person_Ref is access all Person'Class;
type Vehicle_Ref is access all Vehicle'Class;
type Registration_Ref is access all Registration'Class;

Whew!  Got all that out of the way.  Incidently, even though the _Ref 
types are needed in the actual record declarations, there is not 
necessarily a need for the user of the abstractions to be aware of the 
types.  My usual habit is to put them in the private part to start, and 
move them out later if necessary.

Now we can start to declare our registration function:

function Vehicle_Registration (Owner: in out Person;
                                The_Vehicle: in out Vehicle)
                         return Registration;

The compiler promptly slaps our hand.  You can't have a function that 
dispatches on three separate classes.  But in reality, that is not 
really what we wanted anyway.  Let me work this both forward and 
backward.  First, we don't really want to register Vehicles, we want to 
register cars, trucks, motorcycles, buses, boats, etc.  And there may be 
"generic" people, but the base types for Vehicles and Registrations 
should be abstract.

type Vehicle is abstract tagged limited private;
type Registration is abstract tagged limited private;

(It is sort of amazing to me that you often use one or two of abstract, 
tagged, limited, or private in a declaration, but if you need three, you 
usually end up adding the fourth.)

Now in our base package we can see that we want an abstract function for 
registration.  The type of registration returned will be determined 
within the specific function dispatched to, and any special cases 
involving people can be handled by dispatching within the actual 
function.  So what we really wanted was:

abstract function Register(Owner: in out Person'Class;
                            The_Vehicle: in out Vehicle)
                     return Registration'Class;

Perhaps when you finish, you will end up returning a Registration_Ref, 
but so far it isn't necessary to make that type public.  (Notice that 
you can always write Register(Someone, Car)'Access, if you really need 
to get an access value to assign to a Registration_Ref, or in some cases 
Register(Someone, Car)'Unchecked_Access.)

Later you will write (child) packages to deal with cars, trucks, buses, 
and so on.  In cars you will have:

function Register(Owner: in out Person'Class
                   The_Car: in out Automobile)
            return Registration'Class;

You know that you will always return an Automobile_Registration when 
called with an Automobile unless there is a separate 
Temporary_Automobile_Registration.  (You haven't decided on that issue 
yet.)  But AT THE POINT OF THE CALL to the abstract Register, it is not 
known at compile time what type of Registration will be returned.

There is a lot to learn in the above.  Notice that we have used 
classwide parameters or return values for two different reasons in the 
declaration of Register above.  The first occurs in Owner, where the 
owner may be any type derived from Person, and the Register function may 
not need to use internal dispatching on the parameter.  Or, for example, 
  registering a motorcycle may require that the Owner have a license to 
ride motorcycles.  This can be determined by nested dispatching, or more 
usually by "if Owner in Motorcycle_Driver'Class then..."

But the second instance, the use of a classwide result type is more 
interesting.  This is not to cause dispatching, but to actually return 
an object whose class is not known at compile time.  A typical usage is:

procedure Something (...) is
   The_Registration: Registration'Class
              := Register(The_Owner, The_Vehicle);
begin
   -- further operations on The_Registration, which may involve
   -- dispatching calls.
end Something;

> First of all, how do I accomplish returning a reference in Ada? What is the
> default behaviour of parameter passing and return in Ada? Someone said here
> that if I use an "in" parameter in a procedure or function definition, the
> object will be passed by reference. What about the returing of objects? Are
> they returned by copy or returned by reference?

Whether an object is passed by value, value-return, or reference depends 
on the object's class, not on whether the parameter is in, in out, or 
out.  In parameters can be referenced but not changed, in out parameters 
can be referenced and changed, and for out parameters the attributes are 
defined at the point of the call, but there may not be an initial value.

There are tricks you can play in Ada to modify in parameters, and of 
course, if you have an in access value, you may be able to modify the 
value designated. (The may is because the view may be limited.) In 
general, whether a parameter is in, in out, or out is decided to reflect 
the expectations that a user of the subprogram should expect.

> If I use a class-wide type, like My_Type1'Class, what kind of object is
> that? Is it similar to Java's "object.class"?

An object of a class-wide type always has a specific type.  It is just 
that the type may not be determined until the object is created at 
run-time.  Of course, if a class-wide object declaration is nested 
inside a subprogram, the type of the class-wide object--or any 
class-wide parameters--can change each time the subprogram is called.

> What's the difference between passing a class-wide type as an in/out
> parameter of a procedure, and passing an access to it?
> 
> i.e. the difference between
> 
>     procedure Proc( Param : in out Type'Class );
> 
> and
> 
>     type Type_Class_Access is access Type'Class;
>     procedure Proc( Param : in Type_Class_Access );

Not much.  Or rather, using the second form unnecessarily is a sign that 
you are new to Ada.  There are cases where the access parameter won't 
cause any additional difficulties, and other cases where it will mean 
that you need to explicitly free the storage to avoid memory leaks.

If you pass objects instead of pointers, you eliminate the potential 
memory leaks.  This doesn't mean you shouldn't use pointers (access 
types) where appropriate.  But in Ada a good rule is that you only use 
explicit access types to create data structures.  And since you normally 
use abstract data types to implement these structures, the notation is 
limited to the private parts and bodies of a few packages.  (And you 
probably chose those packages from a library instead of "rolling your 
own.")  But sometimes you need to create your own interlinked data 
structures, as in the example of Persons, Vehicles, and Registrations. 
In those cases, you can use different data structure packages, written 
as generics to implement some of the data structures you need.

Incidently, this is my problem with a set of data structure packages as 
a part of Ada.  There are several ways to implement these structures in 
Ada, and which one you want to use depends on intimate details of the 
problem you are trying to solve.  So a limited set of official solutions 
IMHO would be worse than the current situation.  (A core set of data 
structure packages in the standard, plus an indication that compiler 
vendors and others are encouraged to extend the set is a different story.)

> I think I know what run-time dynamic dispatching, class-wide types and
> derived types refer to, but I'm not sure about implicit type conversions
> that I can use.

Don't cheat yourself.  It is possible to subset Ada's support for 
object-oriented programming to match what you currently know about the 
subject from C++ or some other OO languages.  But the Ada model is much, 
much richer than that.  A lot of this richness involves information 
hiding.  In Ada you constantly find yourself asking two questions:

    What is the minimum required information to use this subprogram, 
data-type, abstraction, and so on?

and:

    Is there a different way to express this which allows more 
information hiding?

Why this emphasis on information hiding?  The converse of information 
hiding is coupling.  The more coupling you have, the more bugs you have, 
the bugs are harder to find, and fixing bugs is more likely to create 
additional bugs.  So maximizing information hiding is the easy way to 
bug free programming.

> Like, I'd want to do something similar like this:
> 
>     C := access A;
> 
> In C++, I can just write " C = &A" (if C is a pointer to B). How do I do
> that in Ada?

C := A'Access;

> I tried to use the pointer-like semantics of access to class-wide types, but
> I ended up with doing manual type conversions (or casting) all over. Is that
> normal?

Yes.  Ada is trying to tell you something.  In Ada the intent is that 
cleaner means better.  If you are converting back and forth all over the 
place, it means that your programming model is not well thought out. 
Note that if you really are programming in a scope where you need to do 
such conversions, you can declare your own conversion functions, or 
overload subprograms to take both types of operands:

    type Bar_Ref is access Bar;
    ...
    procedure Foo(in out Bar_Ref) is
    begin Foo(Bar'Access); end Foo;
    pragma Inline(Foo);

But again, if you want or need something like that, it is usually an 
indication of a design problem.

> I thought by using this newsgroup, I could be spared from reading in the Ada
> 95 Rationale. Which is very explicit, but also verbose, and I'd like to make
> my learning process quicker. ;-)

Quicker is possible, but tough.  We used to say that learning Ada was 5% 
learning syntax and 95% learning software engineering.  Then along came 
Ada 95.  It cleaned up a lot of special cases to make learning how to 
program in Ada easier, and added support for several powerful new 
programming paradigms.  My guess is that Ada 95 made learning the 
language somewhat easier, but tripled the amount of software engineering 
you need to know to use the whole language.  You can see that above, 
with delegation of dispatching, multiple dispatch, and returning 
classwide objects.  Those are just from the object-oriented extensions 
in Ada 95.

I could probably teach a one semester course on how to use child 
packages in Ada, and then follow it with a semester on generic package 
parameters in Ada, or a semester on real-time programming in Ada, or a 
semester on high integrity programming, oops make that at least two 
semesters!  I could also probably create a year long course on how to 
use access discriminants in Ada, but IMHO, maybe 30 people world-wide 
need to know all the tricks of using them.  (Maybe a course on when it 
looks like you need to use access discriminants, but don't?)

>               English is a foreign language to me, and I'd rather not
> read umpteen pages of Ada language theory when I can avoid it! ;-) )

Hmmm.  There should be some good Ada reference material auf Deutch, but 
I don't know what offhand.  (And at this point I'm not going to go back 
and rewrite the above. ;-)

-- 
                                           Robert I. Eachus

100% Ada, no bugs--the only way to create software.




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

* Re: Question about OO programming in Ada
  2003-11-26 16:36     ` Martin Krischik
@ 2003-11-26 18:09       ` Robert I. Eachus
  2003-11-27 13:45         ` Jean-Pierre Rosen
  0 siblings, 1 reply; 109+ messages in thread
From: Robert I. Eachus @ 2003-11-26 18:09 UTC (permalink / raw)


Martin Krischik wrote:

> Depends. You can return any non limited type with a function. Ada will will
> use by reference or by value depends what is best. functions however can
> only have in parameters. And you can not return a limited type. 

Nope.  You can have a function that returns a limited type.  The problem 
is that you can't assign the result.  But you can use the function in a 
name to get to a component of the object returned.

Very much a language lawyer point.  We are trying to extend Ada for the 
next revision to make constructors easier to write for limited types.

-- 
 
Robert I. Eachus

100% Ada, no bugs--the only way to create software.




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

* Re: Question about OO programming in Ada
  2003-11-26 15:54     ` Stephen Leake
@ 2003-11-26 20:07       ` Randy Brukardt
  2003-11-26 21:36         ` Stephen Leake
  0 siblings, 1 reply; 109+ messages in thread
From: Randy Brukardt @ 2003-11-26 20:07 UTC (permalink / raw)


"Stephen Leake" <Stephe.Leake@nasa.gov> wrote in message
news:u4qwryvkj.fsf@nasa.gov...
> > > Yikes! The "in" isn't allowed here, nor is the "all" -- they're both
> > > assumed.
> >
> > "in" is allowed, even if assumed. :-)
>
> Hmm. Never make statements like this without first running the code
> thru a compiler. Randy writes compilers and edits the Ada Language
> Reference Manual (you probably did not know this), so he knows what
> he's talking about.

Thanks for the complement, even though it isn't always true. :-)

> "in" is neither assumed nor allowed.

Well, (putting on the language laywer hat), 6.1(18) says that the mode of an
access parameter is 'in'. So in that sense, mode 'in' is assumed - which is
what I meant by the original comment. But it definitely is not allowed to
give 'in' for an access parameter.

                   Randy.







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

* Re: Question about OO programming in Ada
  2003-11-26 20:07       ` Randy Brukardt
@ 2003-11-26 21:36         ` Stephen Leake
  0 siblings, 0 replies; 109+ messages in thread
From: Stephen Leake @ 2003-11-26 21:36 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> "Stephen Leake" <Stephe.Leake@nasa.gov> wrote in message
> news:u4qwryvkj.fsf@nasa.gov...
> > > > Yikes! The "in" isn't allowed here, nor is the "all" -- they're both
> > > > assumed.
> > >
> > > "in" is allowed, even if assumed. :-)
> >
> > Hmm. Never make statements like this without first running the code
> > thru a compiler. Randy writes compilers and edits the Ada Language
> > Reference Manual (you probably did not know this), so he knows what
> > he's talking about.
> 
> Thanks for the complement, even though it isn't always true. :-)
> 
> > "in" is neither assumed nor allowed.
> 
> Well, (putting on the language laywer hat), 6.1(18) says that the mode of an
> access parameter is 'in'. 

To forestall a confusion that often arises in this context: this means
the access value itself can't be changed within the subprogram; the
object pointed to can be.

> So in that sense, mode 'in' is assumed - which is what I meant by
> the original comment. But it definitely is not allowed to give 'in'
> for an access parameter.
> 
>                    Randy.

-- 
-- Stephe



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

* Re: Question about OO programming in Ada
  2003-11-26 17:58     ` Robert I. Eachus
@ 2003-11-27  2:10       ` Ekkehard Morgenstern
  2003-11-27 10:15         ` Ludovic Brenta
                           ` (2 more replies)
  0 siblings, 3 replies; 109+ messages in thread
From: Ekkehard Morgenstern @ 2003-11-27  2:10 UTC (permalink / raw)


First of all, thank you very much for that elaborate reply! :-)
I had to print it out and read it twice to understand it, but it was very
much worth it! :-)

Today I rewrote all my packages to be generic and not use a single access
type! Of course, I had to do away with linked lists. Instead I defined a
parameterized Vector (array) class. Not only has the source become
thrillingly short, but also very easy to handle and inherit from. :-)

This will be sufficient as a foundation to build upon, until I receive the
book "Programming in Ada 95" that I ordered a couple of days ago. :-)

I will try to follow the advice you've given and hide the use of access
types, if I really them, inside the private part of the packages affected.

But I have a few more questions, so it'd be great if you could answer them.
:-)

"Robert I. Eachus" <rieachus@comcast.net> schrieb im Newsbeitrag
news:GpednY19wYJAdFmiRVn-gg@comcast.com...
> That is complex enough to deserve an example.

Thanks for the example, it gave me a good insight into the matter. :-)

> abstract function Register(Owner: in out Person'Class;
>                             The_Vehicle: in out Vehicle)
>                      return Registration'Class;
>
> Perhaps when you finish, you will end up returning a Registration_Ref,
> but so far it isn't necessary to make that type public.  (Notice that
> you can always write Register(Someone, Car)'Access, if you really need
> to get an access value to assign to a Registration_Ref, or in some cases
> Register(Someone, Car)'Unchecked_Access.)

Thanks. That's good to know. What does "Unchecked_Access" do?

> Later you will write (child) packages to deal with cars, trucks, buses,

Why child packages? Does the package hierarchy matter for derived classes?

> ride motorcycles.  This can be determined by nested dispatching, or more
> usually by "if Owner in Motorcycle_Driver'Class then..."

This is really a great feature! So I can practically test if any object is a
member of a particular class, or set of classes?

I read in the OO part of the Rationale that a classwide type is actually
represented internally with a set of key/value pairs, right? What kinds of
other applications does that have?

> But the second instance, the use of a classwide result type is more
> interesting.  This is not to cause dispatching, but to actually return
> an object whose class is not known at compile time.  A typical usage is:
>
> procedure Something (...) is
>    The_Registration: Registration'Class
>               := Register(The_Owner, The_Vehicle);
> begin
>    -- further operations on The_Registration, which may involve
>    -- dispatching calls.
> end Something;

I still wonder if The_Registration is actually a reference, or is it the
object returned by Register()?

I.e. if I wanted only a reference to the object, would I have to use an
access to Registration'Class?

I wonder about this stuff because I'd like implement a linked list package,
which provides one set of subprograms for all types of derived linked lists
and list nodes.

Now, if I had a function like this:

    function Next( N : in out Node'Class ) return Node'Class;

(btw, is it ok to use "in out" in this case with a function?)

Can I return an object of type Node'Class, or do I have to return an access
to it?

And the Node implementation, can it look like this:

    type Node is tagged limited
    record
    Succ : Node'Class;
    Pred : Node'Class;
    end record;

I gather from previous discussions that Node'Class represents an actual
object, not a reference to it, so I'd have to use access types in this case,
which would give

    type Node_Ref is access Node'Class;

    type Node is tagged limited
    record
    Succ : Node_Ref;
    Pred : Node_Ref;
    end record;

Or do I err?

If I use the latter version, and keep the function Next() as defined above,
would the object be copied when it is returned? Or is that precluded by the
fact that it's a limited type?

But if I modify Next() to be something like

    function Next( N : Node_Ref ) return Node_Ref;

how can I avoid casting N and the return value from a derived class?

What's the optimal way in Ada to do this?

> > First of all, how do I accomplish returning a reference in Ada?
>
> Whether an object is passed by value, value-return, or reference depends
> on the object's class, not on whether the parameter is in, in out, or
> out.  In parameters can be referenced but not changed, in out parameters
> can be referenced and changed, and for out parameters the attributes are
> defined at the point of the call, but there may not be an initial value.

But what about return values from functions? Or does the return value in a
function correspond to an "out" parameter in a procedure?


> > i.e. the difference between
> >
> >     procedure Proc( Param : in out Type'Class );
> >
> > and
> >
> >     type Type_Class_Access is access Type'Class;
> >     procedure Proc( Param : in Type_Class_Access );
>
> Not much.  Or rather, using the second form unnecessarily is a sign that
> you are new to Ada.

Yes, I am, but I'm trying to get things right! :-)

> There are cases where the access parameter won't
> cause any additional difficulties, and other cases where it will mean
> that you need to explicitly free the storage to avoid memory leaks.

Yeah, I know that problem can be addressed by creating an instance of the
Unchecked_Deallocation procedure.

BTW, how do I use the Finalization package? I'd like to use things like
constructors and destructors sometimes to be able to initialize / cleanup
objects when they're created or destroyed.

> If you pass objects instead of pointers, you eliminate the potential
> memory leaks.

That's true and a grand feature of Ada because it does away with bookkeeping
on the programmer's part in general.

For now, I'm using arrays where possible instead of lists, which can be
parameterized in generic packages. Then I only need to create an instance of
that package for the application in question, and multiple instances if
necessary. :-)

I'm really surprised how short my source code has become. It's just the way
programming's meant to be that I can concentrate on the key tasks at hand.
:-)

Generic packages remind me a bit of C++ templates, but generics are much
more powerful. :-)

What I also find very useful is the renaming of packages / procedures etc.
Does that have any impact on dispatching or inheritance (in the case of
renaming procedures)?

BTW, can I instantiate a generic package in a procedure body (initialized
with a value passed as a parameter)? (I didn't try yet)


>  This doesn't mean you shouldn't use pointers (access
> types) where appropriate.  But in Ada a good rule is that you only use
> explicit access types to create data structures.  And since you normally
> use abstract data types to implement these structures, the notation is
> limited to the private parts and bodies of a few packages.

I will have to try that with my doubly-linked list problem. Does it really
change much if I use abstract Nodes and Lists in the example I gave above?

The problem with arrays is that they need to be preallocated to a particular
size, which can consume a lot of memory. Lists and Nodes occupy only the
memory that they actually use.

And which method is faster?


> (And you
> probably chose those packages from a library instead of "rolling your
> own.")

What kind of library would you recommend to me? I'd need some linked lists,
queues, containers and so on, but I'd like to have versions that are
completely generic.

I could write them myself, and I probably have to, because I need to limit
the amount of third-party software that I use.

I plan to use Ada for a major software project in which I might even have to
implement an Ada compiler for a virtual machine that I've designed myself,
and which I might also implement in Ada.

That's why it's very important to me to do my packages right, right from the
start, because I perhaps cannot change the design after building up on it.

> But sometimes you need to create your own interlinked data
> structures, as in the example of Persons, Vehicles, and Registrations.
> In those cases, you can use different data structure packages, written
> as generics to implement some of the data structures you need.

Indeed, generics seem to be a very powerful feature in Ada that can be used
in a lot of ways.

> Incidently, this is my problem with a set of data structure packages as
> a part of Ada.  There are several ways to implement these structures in
> Ada, and which one you want to use depends on intimate details of the
> problem you are trying to solve.  So a limited set of official solutions
> IMHO would be worse than the current situation.  (A core set of data
> structure packages in the standard, plus an indication that compiler
> vendors and others are encouraged to extend the set is a different story.)

That's ok. It isn't really all that much code to write such things like
lists, queues, stacks, etc., but of course it would be neat to have them in
the Ada package, because they're constructs frequently used.

> Don't cheat yourself.  It is possible to subset Ada's support for
> object-oriented programming to match what you currently know about the
> subject from C++ or some other OO languages.  But the Ada model is much,
> much richer than that.  A lot of this richness involves information
> hiding.

Yeah I agree. Like in any language, getting a grasp of the language features
might take some time, but it's worth it, of course! :-)


>  In Ada you constantly find yourself asking two questions:
>
>     What is the minimum required information to use this subprogram,
> data-type, abstraction, and so on?

Yeah, I already noticed this today when I rewrote my classes to use
generics. They're only a fraction of the code size they were before. :-)

>
> and:
>
>     Is there a different way to express this which allows more
> information hiding?
>
> Why this emphasis on information hiding?  The converse of information
> hiding is coupling.  The more coupling you have, the more bugs you have,
> the bugs are harder to find, and fixing bugs is more likely to create
> additional bugs.  So maximizing information hiding is the easy way to
> bug free programming.

Yeah, that's true, the more you encapsulate and abstractify classes and
packages as black boxes, the more universally useful they get. :-)

> Yes.  Ada is trying to tell you something.  In Ada the intent is that
> cleaner means better.  If you are converting back and forth all over the
> place, it means that your programming model is not well thought out.

How do I avoid casting access types between derived classes?

> Quicker is possible, but tough.  We used to say that learning Ada was 5%
> learning syntax and 95% learning software engineering.

It's true that learning Ada simple, especially for people who already know
other programming languages.

I can't believe how much I learned in only a couple of days.

Software design is not my problem, it's what I've been doing most of my
life, so it's a piece of cake now that I have Ada. :-)

(Ada can really save a LOT of typing! Just because it has such powerful
constructs. I don't mind at all typing away at packages and stuff knowing
I'd need 10 times the source with C++ or more even with C)

> Then along came
> Ada 95.  It cleaned up a lot of special cases to make learning how to
> program in Ada easier, and added support for several powerful new
> programming paradigms.  My guess is that Ada 95 made learning the
> language somewhat easier, but tripled the amount of software engineering
> you need to know to use the whole language.  You can see that above,
> with delegation of dispatching, multiple dispatch, and returning
> classwide objects.  Those are just from the object-oriented extensions
> in Ada 95.

Yes, but you don't really need to know about all these things to program in
Ada, and that's really a good thing. You can get along well with basic
constructs, and the more intricate details of the language can be postponed
to be used later when necessary.

> I could probably teach a one semester course on how to use child
> packages in Ada, and then follow it with a semester on generic package
> parameters in Ada, or a semester on real-time programming in Ada, or a
> semester on high integrity programming, oops make that at least two
> semesters!  I could also probably create a year long course on how to
> use access discriminants in Ada, but IMHO, maybe 30 people world-wide
> need to know all the tricks of using them.  (Maybe a course on when it
> looks like you need to use access discriminants, but don't?)

You can put me on that list for some later point in time. ;-)

I hope I can get back to you with my questions when I have to write an Ada
compiler and run-time system.

Perhaps my understanding of the language will be real good by then, but I
might still need detailed information about how things are supposed to be.

> >               English is a foreign language to me, and I'd rather not
> > read umpteen pages of Ada language theory when I can avoid it! ;-) )
>
> Hmmm.  There should be some good Ada reference material auf Deutch, but
> I don't know what offhand.  (And at this point I'm not going to go back
> and rewrite the above. ;-)

Yeah, that'd be a lot of work! ;-)

I haven't looked yet for some German-language Ada resources, but I don't
really need them right now. It's a shame, I found no Ada books in German for
beginners on Amazon. But I prefer reading the English language versions to
German translations anyway. :-)

> 100% Ada, no bugs--the only way to create software.

That sounds promising! :-)

I hope I'll be able to write all my future software, at least in my private
projects, in Ada. It has a lot of features I always wanted in a programming
language. And it's a great programming language concept anyway, mature and
tested! (I came up with similar designs on my own and found Ada by
curiousity, recalling a hint that someone gave to me over ten years ago.)
Ada is indeed the best programming language I've ever seen and it seems to
be relatively easy to write a compiler for (like, compared with C++),
because of the logical and well-defined structure. And it has many features
that I haven't found in any other language yet, like value range checking
and arbitrary numerical types, and parameterizable packages.

All of Ada's features are very promising for the development of
well-designed bug-free software. :-)
(because, you know, I'm not worried about myself there, because I can write
bug-free software in any programming language, but if I write a development
environment with its own language, I want to choose a language that enforces
or at least encourages bug-free programming for those less experienced than
people like me, also, and Ada seems to be the ideal choice! Even if I
support other languages -- if my VM is designed for Ada, and Ada is the
prime language for it, then all other languages can benefit from it as
well.)






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

* Re: Question about OO programming in Ada
  2003-11-27  2:10       ` Ekkehard Morgenstern
@ 2003-11-27 10:15         ` Ludovic Brenta
  2003-11-27 18:35         ` Jeffrey Carter
  2003-11-27 22:12         ` Robert I. Eachus
  2 siblings, 0 replies; 109+ messages in thread
From: Ludovic Brenta @ 2003-11-27 10:15 UTC (permalink / raw)


"Ekkehard Morgenstern" writes:

[...]

> "Robert I. Eachus" writes:
[...]
> > abstract function Register(Owner: in out Person'Class;
> >                             The_Vehicle: in out Vehicle)
> >                      return Registration'Class;
> >
> > Perhaps when you finish, you will end up returning a Registration_Ref,
> > but so far it isn't necessary to make that type public.  (Notice that
> > you can always write Register(Someone, Car)'Access, if you really need
> > to get an access value to assign to a Registration_Ref, or in some cases
> > Register(Someone, Car)'Unchecked_Access.)
> 
> Thanks. That's good to know. What does "Unchecked_Access" do?

Assuming

The_Registration : Registration'Class := Register (Someone, Car);

The_Registration'Access returns an access to The_Registration, but the
language rules make sure that there cannot be any "dangling
references" to The_Registration.  In other words, the compiler checks
that the lifetime of The_Registration exceeds the lifetime of the
The_Registration'Access.  In a few cases, the compiler cannot ensure
this statically at compile time, so it inserts run-time checks
instead.  These checks raise Program_Error at run time if they fail.

With Unchecked_Access, these rules are relaxed.  Essentially, if you
use Unchecked_Access, you are telling the compiler that you understand
the issue of dangling references, and that you are dealing with this
issue yourself.

For more insight, see the reference manual: 3.10.2 and 13.10.  The RM
is available on the web:

http://www.adaic.org/standards/95lrm/html/RM-TTL.html
http://www.adaic.org/standards/95lrm/html/RM-3-10-2.html
http://www.adaic.org/standards/95lrm/html/RM-13-10.html

[...]

> > Later you will write (child) packages to deal with cars, trucks, buses,
> 
> Why child packages? Does the package hierarchy matter for derived classes?

Child packages can see the private part of their parent's
specification.  You use them when you require access to the internal
definition of a data structure while still enjoying the benefits of
separate compilation and of specifications.  For example, if you have
a type Registration_Ref which is in the private part of the parent
package, then you can use that type in the child packages.

In OO programming, this is how you'd implement the equivalent of C++
"protected" methods, e.g.

package Parent is
   type Root_Class is tagged private;
   procedure Public_Method (Object : in out Root_Class);
private
   procedure Protected_Method (Object : in out Root_Class);
   type Root_Class is tagged record
      -- ...
   end record;
end Parent;

package Parent.Child is
   type Derived_Class is new Root_Class with private;
   procedure Public_Method (Object : in out Derived_Class);
   -- override the parent's method.
private
   type Derived_Class is new Root_Class with record
      -- ...
   end Derived_Class;
end Parent.Child;

package body Parent.Child is
   procedure Public_Method (Object : in out Derived_Class) is
   begin
      Protected_Method (Object); -- visible from child package
   end Public_Method;
end Parent.Child;

> > ride motorcycles.  This can be determined by nested dispatching, or more
> > usually by "if Owner in Motorcycle_Driver'Class then..."
> 
> This is really a great feature! So I can practically test if any object is a
> member of a particular class, or set of classes?

Yes.  But note that, in Ada, a class is a set of types, whereas in C++
a class is a set of objects.  So a more appropriate wording for the
feature would be that you can test that an object belongs to a type or
a set of types (with 'Class).  Here, "if Owner in
Motorcycle_Driver'Class then..." really means "if Owner is a
Motorcycle_Driver or any type derived from Motorcycle_Driver".

[...]
> I read in the OO part of the Rationale that a classwide type is actually
> represented internally with a set of key/value pairs, right? What kinds of
> other applications does that have?
> 
> > But the second instance, the use of a classwide result type is more
> > interesting.  This is not to cause dispatching, but to actually return
> > an object whose class is not known at compile time.  A typical usage is:
> >
> > procedure Something (...) is
> >    The_Registration: Registration'Class
> >               := Register(The_Owner, The_Vehicle);
> > begin
> >    -- further operations on The_Registration, which may involve
> >    -- dispatching calls.
> > end Something;
> 
> I still wonder if The_Registration is actually a reference, or is it the
> object returned by Register()?

It is the object returned by Register.  But the actual type of the
object is not known at compile time.  All we know is that
The_Registration is either a Registration, or any type derived from
Registration.

> I.e. if I wanted only a reference to the object, would I have to use an
> access to Registration'Class?

Yes.

> I wonder about this stuff because I'd like implement a linked list package,
> which provides one set of subprograms for all types of derived linked lists
> and list nodes.

Here is a quick program that I wrote for the same purposes a while
ago.  It is a "polymorphic list", i.e. a linked list containing nodes
of different types derived from List_Item.  There are primitive
operations on List that do not care what the actual type of each node
is; others (the Put procedures) are primitive operations on the
specific node types.  These are dynamically dispatching.

with Ada.Text_IO;

procedure Polymorphic_List is

   -------------------------------------------------------------------------
   package List is

      type List_Item;
      type List_Item_Access is access List_Item'Class;
      type List_Item is abstract tagged record
         Next_Item : List_Item_Access;
      end record;

      function Find_Last_Item(In_List : in List_Item_Access)
                             return List_Item_Access;

      procedure Add_Item(To : in out List_Item_Access;
                         What : in List_Item_Access);

      procedure Put(What : in List_Item) is abstract;
   end List;


   -------------------------------------------------------------------------
   package body List is

      function Find_Last_Item(In_List : in List_Item_Access)
                             return List_Item_Access
      is
         Previous : List_Item_Access := null;
         Current : List_Item_Access := In_List;
      begin
         while Current /= null loop
            Previous := Current;
            Current := Current.Next_Item;
         end loop;
         return Previous;
      end Find_Last_Item;

      procedure Add_Item(To : in out List_Item_Access;
                         What : in List_Item_Access)
      is
         Last_Item : List_Item_Access := Find_Last_Item(To);
      begin
         if What /= null then
            if Last_Item = null then
               To := What;
            else
               Last_Item.Next_Item := What;
            end if;
         end if;
      end Add_Item;

   end List;

   -------------------------------------------------------------------------

   package Parts is
      type Part_Identifier is (Part_A, Part_B);

      type Part(Text_Size : Positive) is new List.List_Item with record
         Part_Id : Part_Identifier;
         Text : String(1 .. Text_Size);
      end record;

      procedure Put(What : in Part);

      type Component is new List.List_Item with null record;

      procedure Put(What : in Component);

      type Component_B is new List.List_Item with null record;

      procedure Put(What : in Component_B);
   end Parts;

   -------------------------------------------------------------------------

   package body Parts is
      procedure Put(What : in Part) is
      begin
         Ada.Text_Io.Put_Line("Part found of type " &
                              Part_Identifier'Image(What.Part_Id) &
                              " with description """ &
                              What.Text & """");
      end Put;

      procedure Put(What : in Component) is
      begin
         Ada.Text_Io.Put_Line("Component found.");
      end Put;

      procedure Put(What : in Component_B) is
      begin
         Ada.Text_Io.Put_Line("Component_B found.");
      end Put;
   end Parts;

   The_Linked_List : List.List_Item_Access := null;

   Part_Description : constant String := "Some text for part A";
begin -- processing for Polymorphic_List

   -- TODO : initialise all the fields of Part.
   List.Add_Item(To => The_Linked_List,
                 What => new Parts.Part(Text_Size => Part_Description'Length));

   List.Add_Item(To => The_Linked_List,
                 What => new Parts.Component_B);

   List.Add_Item(To => The_Linked_List,
                 What => new Parts.Component);

   declare
      Iterator : List.List_Item_Access := The_Linked_List;
      use List; -- bring in "/=" and Put
   begin
      while Iterator /= null loop
         Ada.Text_Io.Put_Line("Found an item:");
         Put(Iterator.all);
         Iterator := Iterator.Next_Item;
      end loop;
   end;
end Polymorphic_List;


[...]
> Now, if I had a function like this:
> 
>     function Next( N : in out Node'Class ) return Node'Class;
> 
> (btw, is it ok to use "in out" in this case with a function?)
> 
> Can I return an object of type Node'Class, or do I have to return an access
> to it?

You must return an object of type Node, or of any type derived from
Node.  Not an access.  You cannot use "in out" in functions.

> And the Node implementation, can it look like this:
> 
>     type Node is tagged limited
>     record
>     Succ : Node'Class;
>     Pred : Node'Class;
>     end record;

I don't think so.  For one thing, the size of a Node would vary
depending on the actual type of Succ and Pred.  For another, not all
types in Node'Class are known, as more types may be added in the
future.  This is where you need an "access Node'Class".

[...]
> I gather from previous discussions that Node'Class represents an actual
> object, not a reference to it, so I'd have to use access types in this case,
> which would give
> 
>     type Node_Ref is access Node'Class;
> 
>     type Node is tagged limited
>     record
>     Succ : Node_Ref;
>     Pred : Node_Ref;
>     end record;
> 
> Or do I err?

This is correct, but to be more precise, Node'Class represents any
specific type (not object) in the hierarchy of types rooted at Node.

> If I use the latter version, and keep the function Next() as defined above,
> would the object be copied when it is returned? Or is that precluded by the
> fact that it's a limited type?

All tagged and limited types are passed by reference no matter what,
so no copying would take place.

> But if I modify Next() to be something like
> 
>     function Next( N : Node_Ref ) return Node_Ref;
> 
> how can I avoid casting N and the return value from a derived class?
> 
> What's the optimal way in Ada to do this?

Here, you wouldn't have to cast, because all objects of type Node or
derived from Node will have a Next member.  Alternatively, Next could
call a dispatching operation on Node_Ref.

[...]
> > > First of all, how do I accomplish returning a reference in Ada?
> >
> > Whether an object is passed by value, value-return, or reference depends
> > on the object's class, not on whether the parameter is in, in out, or
> > out.  In parameters can be referenced but not changed, in out parameters
> > can be referenced and changed, and for out parameters the attributes are
> > defined at the point of the call, but there may not be an initial value.
> 
> But what about return values from functions? Or does the return value in a
> function correspond to an "out" parameter in a procedure?

Pretty much, yes.  At least in my understanding.

[...]
> > There are cases where the access parameter won't cause any
> > additional difficulties, and other cases where it will mean that
> > you need to explicitly free the storage to avoid memory leaks.
> 
> Yeah, I know that problem can be addressed by creating an instance
> of the Unchecked_Deallocation procedure.

There is an alternative unique to the Ada language.  As per 13.11(18),
you can declare an access type in a scope that is enclosed inside the
scope of the object type.  The compiler inserts an automatic
deallocation at the point where the access type goes out of scope.
This is a little bit tricky to understand, so here is an example.

with Ada.Finalization;
package Controlled is
   type Object is tagged private;
private
   type Object is new Ada.Finalization.Controlled with null record;
   procedure Initialize (O : in out Object);
   procedure Adjust (O : in out Object);
   procedure Finalize (O : in out Object);
end Controlled;

with Ada.Text_IO;
package body Controlled is
   procedure Initialize (O : in out Object) is
   begin
      Ada.Text_IO.Put_Line ("O is being initialized.");
   end Initialize;

   procedure Adjust (O : in out Object) is
   begin
      Ada.Text_IO.Put_Line ("O is being adjusted.");
   end Adjust;

   procedure Finalize (O : in out Object) is
   begin
      Ada.Text_IO.Put_Line ("O is being finalized.");
   end Finalize;
end Controlled;

with Ada.Text_IO;
with Controlled;
procedure Storage is
   procedure Proc is
      type Object_Access is access Controlled.Object;
      O : Object_Access := new Controlled.Object; -- O allocated.
   begin
      Ada.Text_IO.Put_Line ("Within Proc.");
   end Proc; -- type Object_Access goes out of scope here: O deallocated.

begin
   Ada.Text_IO.Put_Line ("Beginning of Storage.");
   Proc;
   Ada.Text_IO.Put_Line ("End of Storage.");
end Storage;

At execution this gives:
$ ./storage
Beginning of Storage.
O is being initialized.
Within Proc.
O is being finalized.
End of Storage.

(this with GNAT 3.15p on GNU/Linux).

Notice how O is being finalized?  Because the type Object_Access goes
out of scope, the compiler causes O to be deallocated for you.  No
need for Unchecked_Deallocation here, and no memory leak.

> BTW, how do I use the Finalization package? I'd like to use things like
> constructors and destructors sometimes to be able to initialize / cleanup
> objects when they're created or destroyed.

See above.

> BTW, can I instantiate a generic package in a procedure body (initialized
> with a value passed as a parameter)? (I didn't try yet)

Yes, but only in a declare block.  e.g.

procedure Proc is
   -- instantiate here...
begin
   -- statements
   declare
      -- or here.
   begin
      -- statements
   end;
   -- statements
end Proc;

> The problem with arrays is that they need to be preallocated to a
> particular size, which can consume a lot of memory. Lists and Nodes
> occupy only the memory that they actually use.
> 
> And which method is faster?

Arrays are usually faster, because memory allocation is a rather
expensive operation.  The run-time system does quite a lot of
bookkeeping for each allocation and deallocation, so if you allocate N
objects in one time it is better.

Note that arrays can be sized dynamically, e.g.

type Array_Of_Objects is array (Natural range <>) of Object;

procedure Proc (Number_Of_Objects_To_Allocate : in Natural) is
   A : Array_Of_Objects (1 .. Number_Of_Objects_To_Allocate);
begin
   -- process the objects
end Proc;

If you need a structure that can grow and shrink, of if your arrays
can grow very large, one strategy could be a linked list of arrays.

> > (And you probably chose those packages from a library instead of
> > "rolling your own.")
> 
> What kind of library would you recommend to me? I'd need some linked lists,
> queues, containers and so on, but I'd like to have versions that are
> completely generic.

Personally I would recommend Charles
(http://home.earthlink.net/~matthewjheaney/charles) but there are
others.

[...]
> I plan to use Ada for a major software project in which I might even have to
> implement an Ada compiler for a virtual machine that I've designed myself,
> and which I might also implement in Ada.

This is indeed a major undertaking.  Perhaps re-targetting GNAT would
be a cheaper alternative which you would consider.  At least you'd
start with the parser and most of the run-time library already
written.  You'd "only" need a new code generator and a port of the RTL
for the VM.

[...]
> How do I avoid casting access types between derived classes?

By using dynamically dispatching subprograms?

[...]
> All of Ada's features are very promising for the development of
> well-designed bug-free software. :-)
> (because, you know, I'm not worried about myself there, because I can write
> bug-free software in any programming language, but if I write a development
> environment with its own language, I want to choose a language that enforces
> or at least encourages bug-free programming for those less experienced than
> people like me, also, and Ada seems to be the ideal choice! Even if I
> support other languages -- if my VM is designed for Ada, and Ada is the
> prime language for it, then all other languages can benefit from it as
> well.)

Even for very experienced people, I think Ada still helps write
bug-free software.  Of course, you can write bug-free software in any
language.  But Ada reduces the cost of doing that.

-- 
Ludovic Brenta.



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

* Re: Question about OO programming in Ada
  2003-11-26 18:09       ` Robert I. Eachus
@ 2003-11-27 13:45         ` Jean-Pierre Rosen
  0 siblings, 0 replies; 109+ messages in thread
From: Jean-Pierre Rosen @ 2003-11-27 13:45 UTC (permalink / raw)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 580 bytes --]


"Robert I. Eachus" <rieachus@comcast.net> a �crit dans le message news:
1oidnUyrztiicVmiRVn-gg@comcast.com...
> Nope.  You can have a function that returns a limited type.  The problem
> is that you can't assign the result.  But you can use the function in a
> name to get to a component of the object returned.

... or pass it as an actual to a subprogram. Quite common actually:

Put_Line (Standard_Output, "It works!");

--
---------------------------------------------------------
           J-P. Rosen (rosen@adalog.fr)
Visit Adalog's web site at http://www.adalog.fr





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

* Re: Question about OO programming in Ada
  2003-11-27  2:10       ` Ekkehard Morgenstern
  2003-11-27 10:15         ` Ludovic Brenta
@ 2003-11-27 18:35         ` Jeffrey Carter
  2003-11-28  4:35           ` Hyman Rosen
  2003-11-27 22:12         ` Robert I. Eachus
  2 siblings, 1 reply; 109+ messages in thread
From: Jeffrey Carter @ 2003-11-27 18:35 UTC (permalink / raw)


Ekkehard Morgenstern wrote:

> Thanks. That's good to know. What does "Unchecked_Access" do?

In Ada, the emphasis is on creating correct software (as opposed to say, 
C, in which the emphasis is on getting something that runs as quickly as 
possible). So the default in Ada is "safe". Access values obtained by 
'Access are safe: you cannot create a dangling reference with 'Access. 
But Ada is also intended for low-level, real-time software where 
sometimes you are sure something is safe but the compiler cannot be 
sure. For those cases, Ada has "Unchecked_" versions of things. The 
access value obtained by 'Unchecked_Access is not safe; it is possible 
to create dangling references with 'Unchecked_Access. You see the same 
sort of thing, for instance, in type conversions. A normal type 
conversion is checked and safe, but there's also Unchecked_Conversion, 
which typically does nothing (it means "interpret this collection of 
bits as this other type).

> I still wonder if The_Registration is actually a reference, or is it the
> object returned by Register()?
> 
> I.e. if I wanted only a reference to the object, would I have to use an
> access to Registration'Class?
> 
> I wonder about this stuff because I'd like implement a linked list package,
> which provides one set of subprograms for all types of derived linked lists
> and list nodes.

For the kind of stuff Eachus has been showing you, you shouldn't really 
care. About the only time you want to worry about this is if you're 
developing a dynamic data structure.

Speaking of dynamic data structures, an unbounded list is such a beast, 
and of course you would want and need to use access types to implement one.

> 
> Now, if I had a function like this:
> 
>     function Next( N : in out Node'Class ) return Node'Class;
> 
> (btw, is it ok to use "in out" in this case with a function?)

No. All parameters to functions have mode "in". I think there's no point 
in specifying the mode for function parameters, since the default is "in".

> 
> Can I return an object of type Node'Class, or do I have to return an access
> to it?

You can return either, depending on what you're doing. Generally you'd 
want to return Node'Class.

> 
> And the Node implementation, can it look like this:
> 
>     type Node is tagged limited
>     record
>     Succ : Node'Class;
>     Pred : Node'Class;
>     end record;

No. You probably want

type Node;

type Node_Ptr is access Node;

type Node is record
    Prev  : Node_Ptr;
    Value : Element;
    Next  : Node_Ptr;
end record;

where Element is the type of the thing you're storing in the list, 
probably a generic formal type. But you're probably better off using an 
existing list package than writing yet another list.

>>(And you
>>probably chose those packages from a library instead of "rolling your
>>own.")
> 
> What kind of library would you recommend to me? I'd need some linked lists,
> queues, containers and so on, but I'd like to have versions that are
> completely generic.

There are a number of well-tested libraries listed at www.adapower.com 
and www.adaworld.com. I like the PragmAda Reusable Components

http://home.earthlink.net/~jrcarter010/pragmarc.htm

but I may be biased.

-- 
Jeff Carter
"Why don't you bore a hole in yourself and let the sap run out?"
Horse Feathers
49




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

* Re: Question about OO programming in Ada
  2003-11-27  2:10       ` Ekkehard Morgenstern
  2003-11-27 10:15         ` Ludovic Brenta
  2003-11-27 18:35         ` Jeffrey Carter
@ 2003-11-27 22:12         ` Robert I. Eachus
  2003-11-28  6:37           ` Simon Wright
  2 siblings, 1 reply; 109+ messages in thread
From: Robert I. Eachus @ 2003-11-27 22:12 UTC (permalink / raw)


Ekkehard Morgenstern wrote:

> But I have a few more questions, so it'd be great if you could answer them.
> :-)

Ludovic Brenta and Jeffery Carter did a pretty good job of that, but 
there were a couple comments I wanted to add.

> This is really a great feature! So I can practically test if any object is a
> member of a particular class, or set of classes?

As answered elsewhere, actually a set of types, which is what a class is 
in Ada.  But you can do more than that.  You can test for membership in 
any subtype.  The canonical example is "if Today in Weekday..."  where 
Weekday is declared as "subtype Weekday is Day range Monday..Friday;" or 
if necessary for some reason you could check for membership in a range:
"if Today in Monday..Wednesday..."

Again, in Ada you choose the most appropriate way to communicate the 
meaning of the code to the reader, and let the compiler figure out how 
to do what you want.

> I still wonder if The_Registration is actually a reference, or is it the
> object returned by Register()?

Don't wonder, this is information hiding at work.  You expect the 
implementor of the Registration type to export an abstract data type 
(ADT) and operations on it that match your expectations, and the 
documentation.  Whether a Registration is an access type, a record type, 
a controlled record type or even an object of type 
Ada.Strings.Unbounded.Unbounded_String should not matter to any user of 
the package.

This turns out to be another way of saying that Ada allows you to 
enforce that any code outside the declaring package (and possibly child 
packages) that depends on how Registration is represented is a bug.  So 
if you need to change the representation later, the changes are all 
localized.

> I.e. if I wanted only a reference to the object, would I have to use an
> access to Registration'Class?

See above.  The package might export a reference type to be used in 
implementations of other data structures.  But again, what is usually 
exported in Ada is the reference SEMANTICS.  Whether the ADT 
Registration_Ref is a registration number, an access type, or an index 
into a database need not be revealed to the user. It is just a way to 
refer to a Registration.  In Ada, the expectation is that you hide as 
much information as possible.  This makes development, debugging, and 
support of the application much easier.

> Can I return an object of type Node'Class, or do I have to return an access
> to it?

You can do either.  But the usual is to return an object of generic 
formal type Node, then the actual can be whatever you want, including 
Registration'Class.

> But what about return values from functions? Or does the return value in a
> function correspond to an "out" parameter in a procedure?

No, but the difference is pretty subtle.  A function can return an 
object of an unconstrained subtype, or classwide type, and the function 
itself will determine what to return.  In the case of an out procedure 
parameter, any constraints on the object are determined by the caller.

So if a function returns a String, the size of the String (technically 
its bounds) can be determined by the inside the function:

function Weird(X, Y: Integer) return String is
begin return Integer'Image(X*(Y/GCD(X,Y)); end Weird;

With an out parameter, the procedure can access the attributes of the 
object passed by the caller:

procedure Blank(S: out String) is
begin S := (others => ' '); end Blank;

Of course you can explicitly pass attribute values to a string:

function Blank(S: in Positive) return String is
begin return String'(1..S => ' '); end Blank;

X: String(1..Length) := Blank(Length);

> BTW, how do I use the Finalization package? I'd like to use things like
> constructors and destructors sometimes to be able to initialize / cleanup
> objects when they're created or destroyed.

Good idea.  But the real answer to your question is that you should only 
use controlled types directly with more experience.  Otherwise use an 
existing data structure library to do things.  (Or if necessary modify 
existing code to do what you need.)  Getting the "corner cases" of 
memory management is tricky irrespective of the language used, so using 
a well tested package means you won't have to track down very subtle 
memory leaks.  (The usual problem cases are when an exception occurs 
during the creation or freeing of a data structure.)

> I'm really surprised how short my source code has become. It's just the way
> programming's meant to be that I can concentrate on the key tasks at hand.
> :-)

Exactly.  Programming in Ada should be just as hard as getting the 
algorithms right--and no harder.

> What I also find very useful is the renaming of packages / procedures etc.
> Does that have any impact on dispatching or inheritance (in the case of
> renaming procedures)?

Not that you should worry about.  There are again subtle cases where 
renaming will cause static dispatching to replace dynamic dispatching, 
or where renaming makes it easier for the compiler to generate good 
code.  But in general use renaming when it makes your work easier, and 
expect the semantic analysis phase of the compiler to eliminate any 
potential overhead.  I often use renaming to give more meaningful names 
to operations and data types in generic instances.

> BTW, can I instantiate a generic package in a procedure body (initialized
> with a value passed as a parameter)? (I didn't try yet)

Yes you can.  There are some cases involving static nesting levels that 
can cause problems.  For example, packages that create controlled types 
need to be instantiated at library level, either in package 
specifications or bodies.

If you run into a case where this is a problem, the solution is to make 
the procedure a generic procedure, then pass the actual controlled type 
as a generic formal type parameter.

This leads to one of the most powerful aspects of Ada generics:  Generic 
instantiation occurs at run-time, not at compile time.  So it is 
perfectly legitimate to instantiate a generic inside a loop, and expect 
each instance to be different.  (Or more to the point, similar to the 
previous instance only by happenstance.)

Note that for a generic subprogram, there are three or more "freezing" 
points where actuals are matched to formals.  (These are different from 
freezing points in Ada for aspects of a type.)  The first occurs at 
compile time, the second occurs when, at run-time, the generic 
specification is elaborated, and the third occurs when the instance is 
called.  Why "or more"?  A generic package may contain other generic 
declarations, creating a cascade of such parameter freezing points. This 
can be a very powerful tool if used right.

> The problem with arrays is that they need to be preallocated to a particular
> size, which can consume a lot of memory. Lists and Nodes occupy only the
> memory that they actually use.

In Ada it is trickier than that. ;-)  Ada array sizes can be 
dynamic--determined at run-time--and still be the exact size needed.  Or 
you can use data structures like doubling lists.  In a doubling list 
every time it gets full, you allocate a new array twice the size, and 
copy all the current data over.  For a list that only grows, such a 
structure never takes as much as twice the space needed, and the "extra" 
copying averages to between one and two copies per entry.

Or another structure I have used for sparse array implementation.  You 
manage a pool of nodes all allocated from the same heap, but instead of 
allocating one at a time, you allocate an array of 1000 or so.  Since 
you never try to return a part of one of these allocated chunks, it 
minimizes the allocation and freeing overhead.

Note again what makes all this possible in Ada.  The chunk management 
layer was hidden from the sparse matrix implementation, the sparse 
matrix implementation was hidding from the algorithms that used it.  So 
instead of making the overall coding job impossibly complex, I had three 
separate sections of code, all of which were just as complex as they 
needed to be.  I could test the algorithms using a non-sparse matrix 
package, and test the sparse matrix software with an implementation that 
allocated nodes individually.  Then when all the code was complete and 
tested, I could combine it and get the real-time performance that I needed.

> How do I avoid casting access types between derived classes?

By declaring the access type as "access all Foo'Class;" if that is what 
it should be.  Again, if you find yourself writing type conversions 
outside very special circumstances it indicates that you haven't thought 
the design through correctly.  Of course, sometimes you need to convert 
floating-point values to fixed-point or integer, or vice-versa.  And in 
the bodies of operations on derived types you may want to call the 
parent operation, but as I said, there are a few contexts where type 
conversions are expected.

Oh, and note that in Ada, class trees tend to be "bushier."  In the 
Registration example, there might be one parent Registration type and 
all other members of the class would be derived from it directly.  There 
are some cases involving mix-ins where you have a sequence of 
derivations, but usually only the ultimate parent and child are visible 
outside the defining package.

> Yes, but you don't really need to know about all these things to program in
> Ada, and that's really a good thing. You can get along well with basic
> constructs, and the more intricate details of the language can be postponed
> to be used later when necessary.

Exactly, and it was intended that way.  There are two subsets of Ada 
that people learn, the "Pascal superset," everything needed to write 
Pascal programs in Ada, and then the "Ada subset," basically the Pascal 
superset plus packages, attributes, generic instantiations, and 
exceptions.  Then the other separable parts of Ada, OO, programming in 
the large, tasking, writing generic units, etc. can be learned in any order.

> I hope I can get back to you with my questions when I have to write an Ada
> compiler and run-time system.

You have already been warned.  Don't.  Porting GNAT or some other 
existing Ada compiler will save you a huge amount of grief.  A usable 
Ada compiler required about a man-decade of work back in the Ada 83 
days.  By now GNAT, Ada Magic, Rational, and so on would take several 
man-centuries to duplicate.  The front-end, semantic analysis, and 
machine independent optimization phases are each several times the size 
of the code generator, and if you port an existing code generator, you 
will find that the tools are designed to support just that.

-- 
                                           Robert I. Eachus

100% Ada, no bugs--the only way to create software.




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

* Re: Question about OO programming in Ada
  2003-11-27 18:35         ` Jeffrey Carter
@ 2003-11-28  4:35           ` Hyman Rosen
  2003-11-28  7:28             ` Vinzent 'Gadget' Hoefler
  2003-12-01 15:57             ` Martin Krischik
  0 siblings, 2 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-11-28  4:35 UTC (permalink / raw)


Jeffrey Carter wrote:
 > you cannot create a dangling reference with 'Access.

How not? Just deallocate the object to which the pointer points.




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

* Re: Question about OO programming in Ada
  2003-11-27 22:12         ` Robert I. Eachus
@ 2003-11-28  6:37           ` Simon Wright
  2003-11-30  2:51             ` Robert I. Eachus
  0 siblings, 1 reply; 109+ messages in thread
From: Simon Wright @ 2003-11-28  6:37 UTC (permalink / raw)


"Robert I. Eachus" <rieachus@comcast.net> writes:

> subtle memory leaks.  (The usual problem cases are when an exception
> occurs during the creation or freeing of a data structure.)

I'm not at all sure that the Booch Components at
(http://www.pushface.org/components/bc) are safe against this sort of
thing -- that is, against running out of memory while adding an
element to a container. If that is going to be a problem, I would
expect people to be using the bounded forms, which don't allocate
memory (of course, the element may be a controlled type with internal
memory management).

I would have thought that a system where an exception occurs in
manipulating data structures is almost bound to be inconsistent and
needs restarting as soon as possible. Of course if the battle override
switch is on you will carry on as best you can, but you are definitely
at risk.

I doubt you can fix this "merely" by making the containers
exception-safe. No real help having a consistent list if the data in
it is inconsistent! (but always nice to avoid walking off the end of a
list, of course).

-- 
Simon Wright                               100% Ada, no bugs.



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

* Re: Question about OO programming in Ada
  2003-11-28  4:35           ` Hyman Rosen
@ 2003-11-28  7:28             ` Vinzent 'Gadget' Hoefler
  2003-11-28  8:46               ` Dale Stanbrough
  2003-12-01 15:57             ` Martin Krischik
  1 sibling, 1 reply; 109+ messages in thread
From: Vinzent 'Gadget' Hoefler @ 2003-11-28  7:28 UTC (permalink / raw)


Hyman Rosen wrote:

[dangling references]
>Just deallocate the object to which the pointer points.

Show me. Without using Unchecked_Deallocation.

As the name "Unchecked_..." implies this is dangerous and using it
will trigger the alarm to everybody who sees it.


Vinzent.



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

* Re: Question about OO programming in Ada
  2003-11-28  7:28             ` Vinzent 'Gadget' Hoefler
@ 2003-11-28  8:46               ` Dale Stanbrough
  2003-11-28 10:16                 ` Vinzent 'Gadget' Hoefler
  0 siblings, 1 reply; 109+ messages in thread
From: Dale Stanbrough @ 2003-11-28  8:46 UTC (permalink / raw)


Vinzent 'Gadget' Hoefler wrote:

> Hyman Rosen wrote:
> 
> [dangling references]
> >Just deallocate the object to which the pointer points.
> 
> Show me. Without using Unchecked Deallocation.
> 
> As the name "Unchecked ..." implies this is dangerous and using it
> will trigger the alarm to everybody who sees it.


Ada has been designed to get rid of a lot of dangling pointers that
inflict languages like C (such as returning pointers to stack based
variables), but unchecked_deallocation is a useful tool that is
used by many people, so I'm not sure how useful it is to say that
Ada never suffers from this problem, simply by excluding a valid
part of the language.


Dale

-- 
dstanbro@spam.o.matic.bigpond.net.au



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

* Re: Question about OO programming in Ada
  2003-11-28  8:46               ` Dale Stanbrough
@ 2003-11-28 10:16                 ` Vinzent 'Gadget' Hoefler
  0 siblings, 0 replies; 109+ messages in thread
From: Vinzent 'Gadget' Hoefler @ 2003-11-28 10:16 UTC (permalink / raw)


Dale Stanbrough wrote:

>Ada has been designed to get rid of a lot of dangling pointers that
>inflict languages like C (such as returning pointers to stack based
>variables),

Precisely.

>but unchecked_deallocation is a useful tool

Yes, of course.

>that is
>used by many people, so I'm not sure how useful it is to say that
>Ada never suffers from this problem,

I didn't say that. I just wanted to point out that it might be a lot
harder to do so.

>simply by excluding a valid part of the language.

Well, valid point. But what I was trying to say is that you can
identify possibly problematic parts in the code if you see the line
"with Ada.Unchecked_Deallocation;" in a source file in a relatively
easy way.

Of course, it doesn't mean that it isn't possible at all.


Vinzent.



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

* Re: Question about OO programming in Ada
  2003-11-28  6:37           ` Simon Wright
@ 2003-11-30  2:51             ` Robert I. Eachus
  0 siblings, 0 replies; 109+ messages in thread
From: Robert I. Eachus @ 2003-11-30  2:51 UTC (permalink / raw)


Simon Wright wrote:

> "Robert I. Eachus" <rieachus@comcast.net> writes:
> 
> 
>>subtle memory leaks.  (The usual problem cases are when an exception
>>occurs during the creation or freeing of a data structure.)
> > 
> I'm not at all sure that the Booch Components at
> (http://www.pushface.org/components/bc) are safe against this sort of
> thing -- that is, against running out of memory while adding an
> element to a container. If that is going to be a problem, I would
> expect people to be using the bounded forms, which don't allocate
> memory (of course, the element may be a controlled type with internal
> memory management).
> 
> I would have thought that a system where an exception occurs in
> manipulating data structures is almost bound to be inconsistent and
> needs restarting as soon as possible. Of course if the battle override
> switch is on you will carry on as best you can, but you are definitely
> at risk.
> 
> I doubt you can fix this "merely" by making the containers
> exception-safe. No real help having a consistent list if the data in
> it is inconsistent! (but always nice to avoid walking off the end of a
> list, of course).

I think you are confusing two separate things here.  Some libraries are 
more robust than others with respect to internal failures in the 
component library--that is one reason why I favor choice in such things. 
  But any competent Ada programmer will create an abstraction where 
errors/exceptions in code supplied by the user of the ADT will not 
corrupt the ADT itself.

When you have a call to a user supplied routine at a point that would 
corrupt the data structure, all the ADT designer has to do is wrap the 
"callback" in a declare block that keeps the ADT consistent.  In other 
words:

begin
   User_Callback;
exception
   when others =>
      -- fix data structure
      ...
      raise;
end;

I try to avoid the need for such blocks by placing callbacks outside 
critical areas of code, but when necessary I put the recovery code in. 
Note that the callback can be implicit, for example when creating an 
object of a (generic formal private) type that may have initialization code.


-- 
                                           Robert I. Eachus

100% Ada, no bugs--the only way to create software.




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

* Re: Question about OO programming in Ada
  2003-11-28  4:35           ` Hyman Rosen
  2003-11-28  7:28             ` Vinzent 'Gadget' Hoefler
@ 2003-12-01 15:57             ` Martin Krischik
  2003-12-01 16:47               ` Hyman Rosen
                                 ` (2 more replies)
  1 sibling, 3 replies; 109+ messages in thread
From: Martin Krischik @ 2003-12-01 15:57 UTC (permalink / raw)


Hyman Rosen wrote:

> Jeffrey Carter wrote:
>  > you cannot create a dangling reference with 'Access.
> 
> How not? Just deallocate the object to which the pointer points.

How will you do this without using some form of "Unchecked_"?

With Regards

Martin

-- 
mailto://krischik@users.sourceforge.net
http://adacl.sourceforge.net




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

* Re: Question about OO programming in Ada
  2003-12-01 15:57             ` Martin Krischik
@ 2003-12-01 16:47               ` Hyman Rosen
  2003-12-03 18:35                 ` Martin Krischik
  2003-12-01 21:13               ` Jeffrey Carter
  2003-12-02  8:47               ` Dmitry A. Kazakov
  2 siblings, 1 reply; 109+ messages in thread
From: Hyman Rosen @ 2003-12-01 16:47 UTC (permalink / raw)


Martin Krischik wrote:
> How will you do this without using some form of "Unchecked_"?

Why am I limited to not using Unchecked_Deallocation?
This is merely the operation known to C programmers as "free"
and to C++ programmers as "delete". It's used for dealing with
dynamic memory structures, with parts whose lifetime is controlled
explicitly by the program. That's hardly a novel or infrequently
used feature of the language.

I expect that C and C++ programs that don't use free and delete
don't have many dangling references either (although they can
screw up in more ways than Ada can).




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

* Re: Question about OO programming in Ada
  2003-12-01 15:57             ` Martin Krischik
  2003-12-01 16:47               ` Hyman Rosen
@ 2003-12-01 21:13               ` Jeffrey Carter
  2003-12-02  8:47               ` Dmitry A. Kazakov
  2 siblings, 0 replies; 109+ messages in thread
From: Jeffrey Carter @ 2003-12-01 21:13 UTC (permalink / raw)


Martin Krischik wrote:

> Hyman Rosen wrote:
> 
> 
>>Jeffrey Carter wrote:
>> > you cannot create a dangling reference with 'Access.
>>
>>How not? Just deallocate the object to which the pointer points.
> 
> 
> How will you do this without using some form of "Unchecked_"?

'access creates an access value to something that is not allocated by 
the programmer on the heap, so it cannot be deallocated:

declare
    type Integer_Ptr is access all Integer;

    I : aliased Integer;
    P : Integer_Ptr := I'access;
begin
    null;
end;

You cannot deallocate I (except by leaving its scope).

-- 
Jeff Carter
"In the frozen land of Nador they were forced to
eat Robin's minstrels, and there was much rejoicing."
Monty Python & the Holy Grail
70




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

* Re: Question about OO programming in Ada
  2003-12-01 15:57             ` Martin Krischik
  2003-12-01 16:47               ` Hyman Rosen
  2003-12-01 21:13               ` Jeffrey Carter
@ 2003-12-02  8:47               ` Dmitry A. Kazakov
  2003-12-03  9:29                 ` Pascal Obry
  2 siblings, 1 reply; 109+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-02  8:47 UTC (permalink / raw)


On Mon, 01 Dec 2003 16:57:37 +0100, Martin Krischik
<krischik@users.sourceforge.net> wrote:

>Hyman Rosen wrote:
>
>> Jeffrey Carter wrote:
>>  > you cannot create a dangling reference with 'Access.
>> 
>> How not? Just deallocate the object to which the pointer points.
>
>How will you do this without using some form of "Unchecked_"?

Easily if the target is controlled. Consider this:

with Ada.Finalization;
package A is
   type Misty is
      new Ada.Finalization.Limited_Controlled with null record;
   procedure Finalize (X : in out Misty);
end A;

with Text_IO; use Text_IO;
package body A is
   procedure Finalize (X : in out Misty) is
   begin
      Put_Line ("finalized!");
   end Finalize;
end A;

with A;  use A;
with Text_IO;  use Text_IO;
procedure Test is
begin
   Put_Line ("Begin of a scope");
   declare
      type Pointer is access all Misty;
      X : Pointer;
   begin
      X := new Misty; -- This is not dangled!
   end;
   Put_Line ("End of the scope");
end Test;

This program should print;

Begin of a scope
finalized!
End of the scope

All controlled objects allocated by the allocator new, being not
explicity destroyed using Unchecked_Deallocation, will be destroyed
upon finalization of the access type.

--
Regards,
Dmitry Kazakov
http://www.dmitry-kazakov.de



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

* Re: Question about OO programming in Ada
  2003-12-02  8:47               ` Dmitry A. Kazakov
@ 2003-12-03  9:29                 ` Pascal Obry
  2003-12-03 11:26                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 109+ messages in thread
From: Pascal Obry @ 2003-12-03  9:29 UTC (permalink / raw)



Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:

> Easily if the target is controlled. Consider this:
> 
> with Ada.Finalization;
> package A is
>    type Misty is
>       new Ada.Finalization.Limited_Controlled with null record;
>    procedure Finalize (X : in out Misty);
> end A;
> 
> with Text_IO; use Text_IO;
> package body A is
>    procedure Finalize (X : in out Misty) is
>    begin
>       Put_Line ("finalized!");
>    end Finalize;
> end A;
> 
> with A;  use A;
> with Text_IO;  use Text_IO;
> procedure Test is
> begin
>    Put_Line ("Begin of a scope");
>    declare
>       type Pointer is access all Misty;
>       X : Pointer;
>    begin
>       X := new Misty; -- This is not dangled!

Of course it is.

>    end;
>    Put_Line ("End of the scope");
> end Test;
> 
> This program should print;
> 
> Begin of a scope
> finalized!
> End of the scope

And it has a nice memory leak.

> All controlled objects allocated by the allocator new, being not
> explicity destroyed using Unchecked_Deallocation, will be destroyed
> upon finalization of the access type.

There is no magic done by Finalize here ! Finalize gives a chance to the
component implementer to do the memory deallocation for the end user. That's
all.

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"
--|
--| gpg --keyserver wwwkeys.pgp.net --recv-key C1082595



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

* Re: Question about OO programming in Ada
  2003-12-03  9:29                 ` Pascal Obry
@ 2003-12-03 11:26                   ` Dmitry A. Kazakov
  2003-12-03 12:49                     ` Ludovic Brenta
  0 siblings, 1 reply; 109+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-03 11:26 UTC (permalink / raw)


On 03 Dec 2003 10:29:17 +0100, Pascal Obry <p.obry@wanadoo.fr> wrote:

>
>Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:
>
>> All controlled objects allocated by the allocator new, being not
>> explicity destroyed using Unchecked_Deallocation, will be destroyed
>> upon finalization of the access type.
>
>There is no magic done by Finalize here! Finalize gives a chance to the
>component implementer to do the memory deallocation for the end user. That's
>all.

Yes, you are right. Controlled objects will be finalized, but the
memory might be not reclaimed. At least, it seems that ARM does not
require that.

--
Regards,
Dmitry Kazakov
http://www.dmitry-kazakov.de



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

* Re: Question about OO programming in Ada
  2003-12-03 11:26                   ` Dmitry A. Kazakov
@ 2003-12-03 12:49                     ` Ludovic Brenta
  2003-12-03 13:41                       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 109+ messages in thread
From: Ludovic Brenta @ 2003-12-03 12:49 UTC (permalink / raw)


Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:

> On 03 Dec 2003 10:29:17 +0100, Pascal Obry <p.obry@wanadoo.fr> wrote:
> 
> >
> >Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:
> >
> >> All controlled objects allocated by the allocator new, being not
> >> explicity destroyed using Unchecked_Deallocation, will be destroyed
> >> upon finalization of the access type.
> >
> >There is no magic done by Finalize here! Finalize gives a chance to the
> >component implementer to do the memory deallocation for the end user. That's
> >all.
> 
> Yes, you are right. Controlled objects will be finalized, but the
> memory might be not reclaimed. At least, it seems that ARM does not
> require that.

I am confused.  I thought that the storage would be reclaimed when the
access type went out of scope, but I tested it with GNAT 3.15p and it
isn't.  Granted, the ARM doesn't seem to require it, but GNAT has the
following in its reference manual:

    *53*.  The manner of choosing a storage pool for an access type
    when `Storage_Pool' is not specified for the type.  See 13.11(17).

    There are 3 different standard pools used by the compiler when
    `Storage_Pool' is not specified depending whether the type is
    local to a subprogram or defined at the library level and whether
    `Storage_Size'is specified or not.  See documentation in the
    runtime library units `System.Pool_Global', `System.Pool_Size' and
    `System.Pool_Local' in files `s-poosiz.ads', `s-pooglo.ads' and
    `s-pooloc.ads' for full details on the default pools used.

And in s-pooloc.ads it says:

   ----------------------------
   -- Unbounded_Reclaim_Pool --
   ----------------------------

   --  Allocation strategy:

   --    Call to malloc/free for each Allocate/Deallocate
   --    no user specifiable size
   --    Space of allocated objects is reclaimed at pool finalization
   --    Manages a list of allocated objects

   --  Default pool in the compiler for access types locally declared

   type Unbounded_Reclaim_Pool is new [...]

I tried to run a test program in gnatgdb but couldn't check what the
storage pool actually was.  Would anyone care to shed some light on
this?  Now I'm really curious.

-- 
Ludovic Brenta.



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

* Re: Question about OO programming in Ada
  2003-12-03 12:49                     ` Ludovic Brenta
@ 2003-12-03 13:41                       ` Dmitry A. Kazakov
  2003-12-03 14:11                         ` Ludovic Brenta
  2003-12-03 15:44                         ` Hyman Rosen
  0 siblings, 2 replies; 109+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-03 13:41 UTC (permalink / raw)


On 03 Dec 2003 13:49:20 +0100, Ludovic Brenta
<ludovic.brenta@insalien.org> wrote:

>Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:
>
>> On 03 Dec 2003 10:29:17 +0100, Pascal Obry <p.obry@wanadoo.fr> wrote:
>> 
>> >
>> >Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:
>> >
>> >> All controlled objects allocated by the allocator new, being not
>> >> explicity destroyed using Unchecked_Deallocation, will be destroyed
>> >> upon finalization of the access type.
>> >
>> >There is no magic done by Finalize here! Finalize gives a chance to the
>> >component implementer to do the memory deallocation for the end user. That's
>> >all.
>> 
>> Yes, you are right. Controlled objects will be finalized, but the
>> memory might be not reclaimed. At least, it seems that ARM does not
>> require that.
>
>I am confused.  I thought that the storage would be reclaimed when the
>access type went out of scope, but I tested it with GNAT 3.15p and it
>isn't.  Granted, the ARM doesn't seem to require it, but GNAT has the
>following in its reference manual:
>
>    *53*.  The manner of choosing a storage pool for an access type
>    when `Storage_Pool' is not specified for the type.  See 13.11(17).
>
>    There are 3 different standard pools used by the compiler when
>    `Storage_Pool' is not specified depending whether the type is
>    local to a subprogram or defined at the library level and whether
>    `Storage_Size'is specified or not.  See documentation in the
>    runtime library units `System.Pool_Global', `System.Pool_Size' and
>    `System.Pool_Local' in files `s-poosiz.ads', `s-pooglo.ads' and
>    `s-pooloc.ads' for full details on the default pools used.
>
>And in s-pooloc.ads it says:
>
>   ----------------------------
>   -- Unbounded_Reclaim_Pool --
>   ----------------------------
>
>   --  Allocation strategy:
>
>   --    Call to malloc/free for each Allocate/Deallocate
>   --    no user specifiable size
>   --    Space of allocated objects is reclaimed at pool finalization
>   --    Manages a list of allocated objects
>
>   --  Default pool in the compiler for access types locally declared
>
>   type Unbounded_Reclaim_Pool is new [...]
>
>I tried to run a test program in gnatgdb but couldn't check what the
>storage pool actually was.  Would anyone care to shed some light on
>this?  Now I'm really curious.

No storage pool can help, if deallocator is not called. If we continue
the example:

with Ada.Finalization;
with System;  use System;
with System.Storage_Elements;  use System.Storage_Elements;
with System.Storage_Pools;  use System.Storage_Pools;
package A is
   type Misty is
      new Ada.Finalization.Limited_Controlled with null record;
   procedure Finalize (X : in out Misty);
   type Pool is new Root_Storage_Pool with record
      Free   : Storage_Offset := 1;
      Memory : aliased Storage_Array (1..1024);
   end record;
   procedure Allocate
             (  Stack     : in out Pool;
                Place     : out Address;
                Size      : Storage_Count;
                Alignment : Storage_Count
             );
   procedure Deallocate
             (  Stack     : in out Pool;
                Place     : Address;
                Size      : Storage_Count;
                Alignment : Storage_Count
             );
   function Storage_Size (Stack : Pool) return Storage_Count; 
end A;

with Text_IO; use Text_IO;
package body A is
   procedure Finalize (X : in out Misty) is
   begin
      Put_Line ("finalized!");
   end Finalize;
   procedure Allocate
             (  Stack     : in out Pool;
                Place     : out Address;
                Size      : Storage_Count;
                Alignment : Storage_Count
             )  is
   begin -- Alignment is ignored for simplicity sake
      Put_Line ("Allocated");
      Place := Stack.Memory (Stack.Free)'Address;
      Stack.Free := Stack.Free + Size;
   end Allocate;
   procedure Deallocate
             (  Stack     : in out Pool;
                Place     : Address;
                Size      : Storage_Count;
                Alignment : Storage_Count
             )  is
   begin -- Does nothing
      Put_Line ("Deallocated");   
   end Deallocate;
   function Storage_Size (Stack : Pool) return Storage_Count is
   begin
      return 0;
   end Storage_Size; 
end A;

with A;  use A;
with Text_IO;  use Text_IO;
procedure Test is
   Storage : Pool;
begin
   Put_Line ("Begin of a scope");
   declare
      type Pointer is access Misty;
      for Pointer'Storage_Pool use Storage;
      X : Pointer;
   begin
      X := new Misty; -- This is not dangled!
   end;
   Put_Line ("End of the scope");
end Test;

With GNAT Test should print:

Begin of a scope
Allocated
finalized!
End of the scope

So even with a user-defined pool it does not work as "should be".

Of course one could call Unchecked_Deallocation from Finalize as
Pascal noted. But it would be awful for an uncounted number of
reasons. To start with, you never know, who calls Finalize, then you
have no pointer to the object, you can get it, but that will be of a
generic access type, so if you have several pools how do you know,
where the object was allocated? and so on and so far.

--
Regards,
Dmitry Kazakov
http://www.dmitry-kazakov.de



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

* Re: Question about OO programming in Ada
  2003-12-03 13:41                       ` Dmitry A. Kazakov
@ 2003-12-03 14:11                         ` Ludovic Brenta
  2003-12-03 14:45                           ` Dmitry A. Kazakov
  2003-12-03 15:44                         ` Hyman Rosen
  1 sibling, 1 reply; 109+ messages in thread
From: Ludovic Brenta @ 2003-12-03 14:11 UTC (permalink / raw)


Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:

But the GNAT doc says that deallocation occurs when the storage pool
is finalized.  Your example does not demonstrate this since your
storage pool does not override Finalize.

> with Ada.Finalization;
> with System;  use System;
> with System.Storage_Elements;  use System.Storage_Elements;
> with System.Storage_Pools;  use System.Storage_Pools;
> package A is
>    type Misty is
>       new Ada.Finalization.Limited_Controlled with null record;
>    procedure Finalize (X : in out Misty);
>    type Pool is new Root_Storage_Pool with record
>       Free   : Storage_Offset := 1;
>       Memory : aliased Storage_Array (1..1024);
>    end record;
>    procedure Allocate
>              (  Stack     : in out Pool;
>                 Place     : out Address;
>                 Size      : Storage_Count;
>                 Alignment : Storage_Count
>              );
>    procedure Deallocate
>              (  Stack     : in out Pool;
>                 Place     : Address;
>                 Size      : Storage_Count;
>                 Alignment : Storage_Count
>              );
>    function Storage_Size (Stack : Pool) return Storage_Count; 

     procedure Finalize (Stack : in out Pool);

> end A;
> 
> with Text_IO; use Text_IO;
> package body A is
>    procedure Finalize (X : in out Misty) is
>    begin
>       Put_Line ("finalized!");
>    end Finalize;
>    procedure Allocate
>              (  Stack     : in out Pool;
>                 Place     : out Address;
>                 Size      : Storage_Count;
>                 Alignment : Storage_Count
>              )  is
>    begin -- Alignment is ignored for simplicity sake
>       Put_Line ("Allocated");
>       Place := Stack.Memory (Stack.Free)'Address;
>       Stack.Free := Stack.Free + Size;
>    end Allocate;
>    procedure Deallocate
>              (  Stack     : in out Pool;
>                 Place     : Address;
>                 Size      : Storage_Count;
>                 Alignment : Storage_Count
>              )  is
>    begin -- Does nothing
>       Put_Line ("Deallocated");   
>    end Deallocate;
>    function Storage_Size (Stack : Pool) return Storage_Count is
>    begin
>       return 0;
>    end Storage_Size; 

     procedure Finalize (Stack : in out Pool) is
     begin
        Put_Line ("Deallocating all objects.");
        Deallocate (Stack, To_Address (Integer_Address (0)), 0, 0);
     end Finalize;

> end A;
> 
> with A;  use A;
> with Text_IO;  use Text_IO;
> procedure Test is
>    Storage : Pool;
> begin
>    Put_Line ("Begin of a scope");
>    declare
>       type Pointer is access Misty;
>       for Pointer'Storage_Pool use Storage;
>       X : Pointer;
>    begin
>       X := new Misty; -- This is not dangled!
>    end;
>    Put_Line ("End of the scope");
> end Test;
> 
> With GNAT Test should print:
> 
> Begin of a scope
> Allocated
> finalized!

  Deallocating all objects.  (yes, I tested it)
  Deallocated

> End of the scope
> 
> So even with a user-defined pool it does not work as "should be".
> 
> Of course one could call Unchecked_Deallocation from Finalize as
> Pascal noted. But it would be awful for an uncounted number of
> reasons. To start with, you never know, who calls Finalize, then you
> have no pointer to the object, you can get it, but that will be of a
> generic access type, so if you have several pools how do you know,
> where the object was allocated? and so on and so far.

The finalization is not that of the allocated objects, it is that of
the storage pool itself (storage pools are limited controlled).  So,
this scheme actually works pretty well and is quite straightforward to
implement.

The part that I do not understand is why GNAT's Unbounded_Reclaim_Pool
doesn't seem to be selected for a local access type.  I think this
either contradicts the GNAT reference manual, or is an instance of me
not understanding it.

-- 
Ludovic Brenta.



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

* Re: Question about OO programming in Ada
  2003-12-03 14:11                         ` Ludovic Brenta
@ 2003-12-03 14:45                           ` Dmitry A. Kazakov
  0 siblings, 0 replies; 109+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-03 14:45 UTC (permalink / raw)


On 03 Dec 2003 15:11:51 +0100, Ludovic Brenta
<ludovic.brenta@insalien.org> wrote:

>Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:
>
>But the GNAT doc says that deallocation occurs when the storage pool
>is finalized.  Your example does not demonstrate this since your
>storage pool does not override Finalize.

Of course, when storage pool object gets destroyed the memory of the
objects allocated there will be reclaimed (though without calling
Unchecked_Deallocate on them, in a hope that it was already made
before)

>> with Ada.Finalization;
>> with System;  use System;
>> with System.Storage_Elements;  use System.Storage_Elements;
>> with System.Storage_Pools;  use System.Storage_Pools;
>> package A is
>>    type Misty is
>>       new Ada.Finalization.Limited_Controlled with null record;
>>    procedure Finalize (X : in out Misty);
>>    type Pool is new Root_Storage_Pool with record
>>       Free   : Storage_Offset := 1;
>>       Memory : aliased Storage_Array (1..1024);
>>    end record;
>>    procedure Allocate
>>              (  Stack     : in out Pool;
>>                 Place     : out Address;
>>                 Size      : Storage_Count;
>>                 Alignment : Storage_Count
>>              );
>>    procedure Deallocate
>>              (  Stack     : in out Pool;
>>                 Place     : Address;
>>                 Size      : Storage_Count;
>>                 Alignment : Storage_Count
>>              );
>>    function Storage_Size (Stack : Pool) return Storage_Count; 
>
>     procedure Finalize (Stack : in out Pool);
>
>> end A;
>> 
>> with Text_IO; use Text_IO;
>> package body A is
>>    procedure Finalize (X : in out Misty) is
>>    begin
>>       Put_Line ("finalized!");
>>    end Finalize;
>>    procedure Allocate
>>              (  Stack     : in out Pool;
>>                 Place     : out Address;
>>                 Size      : Storage_Count;
>>                 Alignment : Storage_Count
>>              )  is
>>    begin -- Alignment is ignored for simplicity sake
>>       Put_Line ("Allocated");
>>       Place := Stack.Memory (Stack.Free)'Address;
>>       Stack.Free := Stack.Free + Size;
>>    end Allocate;
>>    procedure Deallocate
>>              (  Stack     : in out Pool;
>>                 Place     : Address;
>>                 Size      : Storage_Count;
>>                 Alignment : Storage_Count
>>              )  is
>>    begin -- Does nothing
>>       Put_Line ("Deallocated");   
>>    end Deallocate;
>>    function Storage_Size (Stack : Pool) return Storage_Count is
>>    begin
>>       return 0;
>>    end Storage_Size; 
>
>     procedure Finalize (Stack : in out Pool) is
>     begin
>        Put_Line ("Deallocating all objects.");
>        Deallocate (Stack, To_Address (Integer_Address (0)), 0, 0);
>     end Finalize;
>
>> end A;
>> 
>> with A;  use A;
>> with Text_IO;  use Text_IO;
>> procedure Test is
>>    Storage : Pool;
>> begin
>>    Put_Line ("Begin of a scope");
>>    declare
>>       type Pointer is access Misty;
>>       for Pointer'Storage_Pool use Storage;
>>       X : Pointer;
>>    begin
>>       X := new Misty; -- This is not dangled!
>>    end;
>>    Put_Line ("End of the scope");
>> end Test;
>> 
>> With GNAT Test should print:
>> 
>> Begin of a scope
>> Allocated
>> finalized!
>
>  Deallocating all objects.  (yes, I tested it)
>  Deallocated
>
>> End of the scope
>> 
>> So even with a user-defined pool it does not work as "should be".
>> 
>> Of course one could call Unchecked_Deallocation from Finalize as
>> Pascal noted. But it would be awful for an uncounted number of
>> reasons. To start with, you never know, who calls Finalize, then you
>> have no pointer to the object, you can get it, but that will be of a
>> generic access type, so if you have several pools how do you know,
>> where the object was allocated? and so on and so far.
>
>The finalization is not that of the allocated objects, it is that of
>the storage pool itself (storage pools are limited controlled).  So,
>this scheme actually works pretty well and is quite straightforward to
>implement.

Only if the scope of the access type and the scope of the pool object
are same.

>The part that I do not understand is why GNAT's Unbounded_Reclaim_Pool
>doesn't seem to be selected for a local access type.  I think this
>either contradicts the GNAT reference manual, or is an instance of me
>not understanding it.

But to make it working there should be a new object of
Unbounded_Reclaim_Pool per scope:

declare
   type Pointer is access Controlled_Something;

should be translated into:

declare
   Local_Pool : Unbounded_Reclaim_Pool;
   type Pointer is access Controlled_Something;
   for Pointer'Storage_Pool use Local_Pool;

Theoretically it is possible, but practically? Maybe there is only one
object of Unbounded_Reclaim_Pool [per task?]

--
Regards,
Dmitry Kazakov
http://www.dmitry-kazakov.de



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

* Re: Question about OO programming in Ada
  2003-12-03 13:41                       ` Dmitry A. Kazakov
  2003-12-03 14:11                         ` Ludovic Brenta
@ 2003-12-03 15:44                         ` Hyman Rosen
  2003-12-03 16:11                           ` Dmitry A. Kazakov
                                             ` (4 more replies)
  1 sibling, 5 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-12-03 15:44 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> Of course one could call Unchecked_Deallocation from Finalize

I understand that Ada permits Finalize to be called multiple times
for an object, so calling Unchecked_Deallocation from Finalize sounds
like a recipe for disaster.




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

* Re: Question about OO programming in Ada
  2003-12-03 15:44                         ` Hyman Rosen
@ 2003-12-03 16:11                           ` Dmitry A. Kazakov
  2003-12-03 18:20                           ` David C. Hoos
                                             ` (3 subsequent siblings)
  4 siblings, 0 replies; 109+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-03 16:11 UTC (permalink / raw)


On Wed, 03 Dec 2003 10:44:40 -0500, Hyman Rosen <hyrosen@mail.com>
wrote:

>Dmitry A. Kazakov wrote:
>> Of course one could call Unchecked_Deallocation from Finalize
>
>I understand that Ada permits Finalize to be called multiple times
>for an object, so calling Unchecked_Deallocation from Finalize sounds
>like a recipe for disaster.

Alas

I my view construction / destruction issue should be completely
reworked in Ada. There are too many problems with it now.

--
Regards,
Dmitry Kazakov
http://www.dmitry-kazakov.de



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

* Re: Question about OO programming in Ada
  2003-12-03 15:44                         ` Hyman Rosen
  2003-12-03 16:11                           ` Dmitry A. Kazakov
@ 2003-12-03 18:20                           ` David C. Hoos
       [not found]                           ` <28eb01c3b9ca$25b18870$b101a8c0@sy.com>
                                             ` (2 subsequent siblings)
  4 siblings, 0 replies; 109+ messages in thread
From: David C. Hoos @ 2003-12-03 18:20 UTC (permalink / raw)
  To: Hyman Rosen, comp.lang.ada@ada.eu.org


----- Original Message ----- 
From: "Hyman Rosen" <hyrosen@mail.com>
Newsgroups: comp.lang.ada
To: <comp.lang.ada@ada-france.org>
Sent: Wednesday, December 03, 2003 9:44 AM
Subject: Re: Question about OO programming in Ada


> Dmitry A. Kazakov wrote:
> > Of course one could call Unchecked_Deallocation from Finalize
>
> I understand that Ada permits Finalize to be called multiple times
> for an object, so calling Unchecked_Deallocation from Finalize sounds
> like a recipe for disaster.
>
How is it a "disaster" when RM95 13.11.2 (6-9) says:

6. Procedure Free has the following effect:

7 � After executing Free(X), the value of X is null.
8 � Free(X), when X is already equal to null, has no effect.
9 � Free(X), when X is not equal to null first performs finalization, as
described in 7.6. It then deallocates the storage occupied by the object
designated by X. If the storage pool is a user-defined object, then the
storage is deallocated by calling Deallocate, passing
access_to_variable_subtype_name'Storage_Pool as the Pool parameter.
Storage_Address is the value returned in the Storage_Address parameter of
the corresponding Allocate call. Size_In_Storage_Elements and Alignment are
the same values passed to the corresponding Allocate call. There is one
exception: if the object being freed contains tasks, the object might not be
deallocated.





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

* Re: Question about OO programming in Ada
  2003-12-01 16:47               ` Hyman Rosen
@ 2003-12-03 18:35                 ` Martin Krischik
  0 siblings, 0 replies; 109+ messages in thread
From: Martin Krischik @ 2003-12-03 18:35 UTC (permalink / raw)


Hyman Rosen wrote:

> Martin Krischik wrote:
>> How will you do this without using some form of "Unchecked_"?
> 
> Why am I limited to not using Unchecked_Deallocation?
> This is merely the operation known to C programmers as "free"
> and to C++ programmers as "delete". It's used for dealing with
> dynamic memory structures, with parts whose lifetime is controlled
> explicitly by the program. That's hardly a novel or infrequently
> used feature of the language.
> 
> I expect that C and C++ programs that don't use free and delete
> don't have many dangling references either (although they can
> screw up in more ways than Ada can).

The OP spoke about that all unsafe operation are marked Unchecked_ and this
is what i was refairing to.

With Regards

Martin

-- 
mailto://krischik@users.sourceforge.net
http://adacl.sourceforge.net




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

* Re: Question about OO programming in Ada
       [not found]                           ` <28eb01c3b9ca$25b18870$b101a8c0@sy.com>
@ 2003-12-03 18:35                             ` Hyman Rosen
  0 siblings, 0 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-12-03 18:35 UTC (permalink / raw)
  To: David C. Hoos; +Cc: comp.lang.ada@ada.eu.org

David C. Hoos wrote:
> How is it a "disaster" when RM95 13.11.2 (6-9) says:
> 7 � After executing Free(X), the value of X is null.

Because this affects only the "X" used in the call.
Any other pointers that are holding the same address
will continue to do so. The call to Free in Finalize
would be using the address of the Finalize parameter.
A second call would do the same, causing the pointer
to be freed twice.

> 9 � Free(X), when X is not equal to null first performs finalization

Oh, and if it does that, aren't we going to go into
death by recursion?





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

* Re: Question about OO programming in Ada
  2003-12-03 15:44                         ` Hyman Rosen
                                             ` (2 preceding siblings ...)
       [not found]                           ` <28eb01c3b9ca$25b18870$b101a8c0@sy.com>
@ 2003-12-03 20:05                           ` Randy Brukardt
  2003-12-03 20:57                             ` Hyman Rosen
  2003-12-03 22:04                           ` Pascal Obry
  4 siblings, 1 reply; 109+ messages in thread
From: Randy Brukardt @ 2003-12-03 20:05 UTC (permalink / raw)


"Hyman Rosen" <hyrosen@mail.com> wrote in message
news:1070466281.168920@master.nyc.kbcfp.com...
> Dmitry A. Kazakov wrote:
> > Of course one could call Unchecked_Deallocation from Finalize
>
> I understand that Ada permits Finalize to be called multiple times
> for an object, so calling Unchecked_Deallocation from Finalize sounds
> like a recipe for disaster.

Finalize should handle tasks for the components, not the object itself. So,
it is possible (and common) to call U_D on components of the object
(presuming that you have a way to check that it hasn't already been done, a
requirement of all Finalize routines). But you never do memory allocation on
the top-level object.

This is precisely how Janus/Ada manages complex objects at runtime, so the
technique is so familar to me I always find it surprising that it is not
obvious to others. Leaving allocation of the object itself to it's owner is
necessary in any case: the object may not even have been allocated on the
heap, or may be a component of some other object.

If you want to manage an access value in Ada 95, you wrap it in a controlled
record type and then you can do the allocation/deallocation safely.

                Randy.






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

* Re: Question about OO programming in Ada
  2003-12-03 20:05                           ` Randy Brukardt
@ 2003-12-03 20:57                             ` Hyman Rosen
  2003-12-03 21:16                               ` Hyman Rosen
  0 siblings, 1 reply; 109+ messages in thread
From: Hyman Rosen @ 2003-12-03 20:57 UTC (permalink / raw)


Randy Brukardt wrote:
> Finalize should handle tasks for the components, not the object itself. So,
> it is possible (and common) to call U_D on components of the object
> (presuming that you have a way to check that it hasn't already been done, a
> requirement of all Finalize routines). But you never do memory allocation on
> the top-level object.

That's not true. In C++, it's not uncommon for objects to have
     delete this;
in their destructors. The technique is used for objects which
manage their own lifetimes, and know when it's time to go.
Reference counted objects are an example of this - the count
is decremented in the destructor, and if it reaches zero, the
object deletes itself. No muss, no fuss.

The technique does require that a destructor will be called
exactly once for an object. C++ guarantees this, Ada does not.




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

* Re: Question about OO programming in Ada
  2003-12-03 20:57                             ` Hyman Rosen
@ 2003-12-03 21:16                               ` Hyman Rosen
  0 siblings, 0 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-12-03 21:16 UTC (permalink / raw)


Sorry - I confused myself. Rather, in C++ objects can have
methods (not the destructor!) which call 'delete this;'.




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

* Re: Question about OO programming in Ada
  2003-12-03 15:44                         ` Hyman Rosen
                                             ` (3 preceding siblings ...)
  2003-12-03 20:05                           ` Randy Brukardt
@ 2003-12-03 22:04                           ` Pascal Obry
  2003-12-03 22:34                             ` Hyman Rosen
  4 siblings, 1 reply; 109+ messages in thread
From: Pascal Obry @ 2003-12-03 22:04 UTC (permalink / raw)



Hyman Rosen <hyrosen@mail.com> writes:

> Dmitry A. Kazakov wrote:
> > Of course one could call Unchecked_Deallocation from Finalize
> 
> I understand that Ada permits Finalize to be called multiple times
> for an object, so calling Unchecked_Deallocation from Finalize sounds
> like a recipe for disaster.

Certainly not! Unchecked_Deallocation will set the pointer to null and
Unchecked_Deallocation on a null pointer does nothing.

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"
--|
--| gpg --keyserver wwwkeys.pgp.net --recv-key C1082595



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

* Re: Question about OO programming in Ada
  2003-12-03 22:04                           ` Pascal Obry
@ 2003-12-03 22:34                             ` Hyman Rosen
  2003-12-04  1:23                               ` Robert I. Eachus
  0 siblings, 1 reply; 109+ messages in thread
From: Hyman Rosen @ 2003-12-03 22:34 UTC (permalink / raw)


Pascal Obry wrote:
> Certainly not! Unchecked_Deallocation will set the pointer to null and
> Unchecked_Deallocation on a null pointer does nothing.

Not on a pointer field within the object, but on the object itself.




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

* Re: Question about OO programming in Ada
  2003-12-03 22:34                             ` Hyman Rosen
@ 2003-12-04  1:23                               ` Robert I. Eachus
  2003-12-04  7:15                                 ` Hyman Rosen
  2003-12-04  8:55                                 ` Dmitry A. Kazakov
  0 siblings, 2 replies; 109+ messages in thread
From: Robert I. Eachus @ 2003-12-04  1:23 UTC (permalink / raw)


Hyman Rosen wrote:

> Not on a pointer field within the object, but on the object itself.

I'm very confused about why Hyman is confused.  Making a copy of an 
access value in Ada, and calling Free for both the original and the copy 
is bad juju.  Calling Free twice, or twenty times and passing the only 
the original access object is never a problem.

Ah, I think I get it.  In C there are many occasions where a function 
will return a heap object, and it is up to the caller to free the 
memory.  The returned value can be a copy of the original pointer, so in 
C it is relatively common to free a copy of the original heap pointer. 
That may be what is confusing Hyman.

In Ada is it very rare, and usually an error if you call Free for an 
object or value that was not assigned a value by new.  Normally in 
Finalize procedures this is a record parameter.

Freeing the entire record that was the parameter of a Finalize procedure 
is possible to write,  but you end up assigning Foo'Access to something 
then freeing it.  (If you try to call Free on a access discriminant, it 
won't work.)  As the previous paragraph says, to any Ada programmer that 
looks like big trouble, and it is.

-- 
                                           Robert I. Eachus

100% Ada, no bugs--the only way to create software.




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

* Re: Question about OO programming in Ada
  2003-12-04  1:23                               ` Robert I. Eachus
@ 2003-12-04  7:15                                 ` Hyman Rosen
  2003-12-04 17:43                                   ` Warren W. Gay VE3WWG
  2003-12-04  8:55                                 ` Dmitry A. Kazakov
  1 sibling, 1 reply; 109+ messages in thread
From: Hyman Rosen @ 2003-12-04  7:15 UTC (permalink / raw)


Robert I. Eachus wrote:
> Ah, I think I get it.  In C there are many occasions where a function 
> will return a heap object, and it is up to the caller to free the 
> memory.  The returned value can be a copy of the original pointer, so in 
> C it is relatively common to free a copy of the original heap pointer. 
> That may be what is confusing Hyman.

I'm confused about whether I'm confused :-)

Anyway, C++ doesn't set a pointer variable to null when you free its contents.
Since you should be doing this in destructors most of the time, it doesn't matter,
because the pointer variable will very shortly not exist.

Now, as I said, in C++ sometimes objects will delete themselves:
     struct A {
         int refcount;
         void decr() { if (--refcount == 0) delete this; }
         // etc.
     };




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

* Re: Question about OO programming in Ada
  2003-12-04  1:23                               ` Robert I. Eachus
  2003-12-04  7:15                                 ` Hyman Rosen
@ 2003-12-04  8:55                                 ` Dmitry A. Kazakov
  2003-12-04 19:13                                   ` Randy Brukardt
  2003-12-04 21:32                                   ` Robert I. Eachus
  1 sibling, 2 replies; 109+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-04  8:55 UTC (permalink / raw)


On Wed, 03 Dec 2003 20:23:53 -0500, "Robert I. Eachus"
<rieachus@comcast.net> wrote:

>Hyman Rosen wrote:
>
>> Not on a pointer field within the object, but on the object itself.
>
>I'm very confused about why Hyman is confused.  Making a copy of an 
>access value in Ada, and calling Free for both the original and the copy 
>is bad juju.  Calling Free twice, or twenty times and passing the only 
>the original access object is never a problem.

It is worth to write a sample code to the problem:

with Ada.Finalization;
package B is
   type Object is
      new Ada.Finalization.Limited_Controlled with
   record
      Got_It : Boolean := False; -- Prevents recursion
   end record;
   procedure Finalize (X : in out Object);
end B;

with Ada.Unchecked_Deallocation;
with Text_IO;  use Text_IO;
package body B is
   type Object_Ptr is access all Object'Class;
   procedure Free is
      new Ada.Unchecked_Deallocation (Object'Class, Object_Ptr);
   procedure Finalize (X : in out Object) is
      Ptr : Object_Ptr := X'Unchecked_Access;
   begin
      if not X.Got_It then
         X.Got_It := True;
         Put_Line ("Deallocation");
         Free (Ptr);
      end if;
   end Finalize;
end B;

Intended to mend this:

with B; use B;
with Text_IO; use Text_IO;
procedure Test1 is
begin
   Put_Line ("Begin of the scope");
   declare
      type Pointer is access Object;
      X : Pointer;
   begin
      X := new Object; -- This is not dangled!
   end;
   Put_Line ("End of the scope");
end Test1;

The point is that calling Free from Finalize is revolting. This would
not be necessary if finalization of the type Pointer called
deallocator in addition to a call to Finalize.

--
Regards,
Dmitry Kazakov
http://www.dmitry-kazakov.de



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

* Re: Question about OO programming in Ada
  2003-12-04  7:15                                 ` Hyman Rosen
@ 2003-12-04 17:43                                   ` Warren W. Gay VE3WWG
  0 siblings, 0 replies; 109+ messages in thread
From: Warren W. Gay VE3WWG @ 2003-12-04 17:43 UTC (permalink / raw)


Hyman Rosen wrote:
> Robert I. Eachus wrote:
> 
>> Ah, I think I get it.  In C there are many occasions where a function 
>> will return a heap object, and it is up to the caller to free the 
>> memory.  The returned value can be a copy of the original pointer, so 
>> in C it is relatively common to free a copy of the original heap 
>> pointer. That may be what is confusing Hyman.
> 
> I'm confused about whether I'm confused :-)
> 
> Anyway, C++ doesn't set a pointer variable to null when you free its 
> contents.
> Since you should be doing this in destructors most of the time, it 
> doesn't matter,
> because the pointer variable will very shortly not exist.

Even in that case, you may still want to null the pointer. This
can be helpful in debugging. An errant program may still try to
use the object (now freed), and attempt to use the pointers
contained within it. There is a better chance of the program
failing (and getting fixed), if the pointers are now null.

The reverse is true if the pointers are still there and are
being used as buffers etc.. leading to strange and difficult
to debug problems.
-- 
Warren W. Gay VE3WWG
http://home.cogeco.ca/~ve3wwg




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

* Re: Question about OO programming in Ada
  2003-12-04  8:55                                 ` Dmitry A. Kazakov
@ 2003-12-04 19:13                                   ` Randy Brukardt
  2003-12-04 19:29                                     ` Hyman Rosen
  2003-12-04 21:32                                   ` Robert I. Eachus
  1 sibling, 1 reply; 109+ messages in thread
From: Randy Brukardt @ 2003-12-04 19:13 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
news:2prtsvgmt5lt3u1ulb5dvh8ba5nulfl3l3@4ax.com...
> The point is that calling Free from Finalize is revolting. This would
> not be necessary if finalization of the type Pointer called
> deallocator in addition to a call to Finalize.

It's not just revolting, it's dangerous. What if "Object" is declared
locally:

    declare
        X : Object;
    begin

You're giving the heap memory that isn't its in the first place.

More commonly, Object will be a component of some other record. In either
case, having a "hidden" restriction that Object can only be allocated (the
thing you want to avoid when possible!) is really, really dumb.

I'd expect that to be true in C++ as well -- or does C++ not even allow
statically allocated class objects and class components? (If they always
have to be allocated from the heap, there is no problem.)

                       Randy.






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

* Re: Question about OO programming in Ada
  2003-12-04 19:13                                   ` Randy Brukardt
@ 2003-12-04 19:29                                     ` Hyman Rosen
  0 siblings, 0 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-12-04 19:29 UTC (permalink / raw)


Randy Brukardt wrote:
> I'd expect that to be true in C++ as well -- or does C++ not even allow
> statically allocated class objects and class components? (If they always
> have to be allocated from the heap, there is no problem.)

C++ does allow for statically allocated objects.
For objects which manage their own lifetime,
you would like to disable that, and how to do
that is an FAQ. You make the destructor and the
array allocator private:

     class heap_only
     {
         ~heap_only() { }
         void *operator new[](size_t);
     public:
         free() { delete this; }
     };

Now you can say
     heap_only *p = new heap_only; // allocate one
     p->free();                    // free it
but not
     heap_only h;  // error - can't access destructor




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

* Re: Question about OO programming in Ada
  2003-12-04  8:55                                 ` Dmitry A. Kazakov
  2003-12-04 19:13                                   ` Randy Brukardt
@ 2003-12-04 21:32                                   ` Robert I. Eachus
  2003-12-05  8:43                                     ` Dmitry A. Kazakov
  1 sibling, 1 reply; 109+ messages in thread
From: Robert I. Eachus @ 2003-12-04 21:32 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> On Wed, 03 Dec 2003 20:23:53 -0500, "Robert I. Eachus"
> <rieachus@comcast.net> wrote:
> 
> 
>>Hyman Rosen wrote:
>>
>>
>>>Not on a pointer field within the object, but on the object itself.
>>
>>I'm very confused about why Hyman is confused.  Making a copy of an 
>>access value in Ada, and calling Free for both the original and the copy 
>>is bad juju.  Calling Free twice, or twenty times and passing the only 
>>the original access object is never a problem.
> 
> 
> It is worth to write a sample code to the problem:
> 
> with Ada.Finalization;...
 >
> The point is that calling Free from Finalize is revolting.

Yes, that is exactly the code you should never write.  If you have an 
object which is always designated by an access value, and you want the 
object to be deallocated "automagically," the Ada solution is to make 
the access variable a component of a record:

with Ada.Finalization;
package B is
    type Object_Ref is
       new Ada.Finalization.Limited_Controlled with private;
    record
       Got_It : Boolean := False; -- Prevents recursion
    end record;
    procedure Finalize (X : in out Object);

private

    type Object is limited...;
    type Object_Ptr is access Object'Class;
    type Object_Ref is
       new Ada.Finalization.Limited_Controlled with
    record
       Obj: Object_Ptr := new Object;
    end record;

end B;

with Ada.Unchecked_Deallocation;
with Text_IO;  use Text_IO;
package body B is

    procedure Free is
       new Ada.Unchecked_Deallocation (Object_Ref'Class, Object_Ptr);
    procedure Finalize (X : in out Object_Ref) is
    begin
       Free (X.Obj);
       Put_Line ("Deallocation");
    end Finalize;
end B;

with B; use B;
with Text_IO; use Text_IO;
procedure Test1 is
begin
    Put_Line ("Begin of the scope");
    declare
       X : Object_Ref; -- allocation done here.
    begin
      null;
    end; -- Finalize called here.
    Put_Line ("End of the scope");
end Test1;

There are lots of variations on this theme, including a version where 
Object_Ref is not limited and there is an Adjust, or where the allocator 
   is in an Initialize routine.  But this is the standard Ada 95 idiom 
for managing objects which must be on the stack.  The "pointer type" is 
a controlled record with an access type to the 'real' data on the heap.

But notice that the original version is a live hand grenade that can be 
set off in three ways.  If you create a Object on the stack, if an 
Object is not properly initialized, or if Finalize gets called more than 
once.   The 'clever' code to check Got_It is no real protection in the 
third case.  The storage designated by a junk pointer can have any value 
for Got_It.  In the second case, it may prevent deallocating an object 
that was never initialized, but that is a relatively minor problem 
(storage leak) compared to the other failure cases.

 >                                                     This would
 > not be necessary if finalization of the type Pointer called
 > deallocator in addition to a call to Finalize.

Think about this for a second, because there is a germ of a good idea 
here.  For access types for which assignment is valid, such a rule would 
be a disaster.  For example you don't want the next record in a linked 
list, and for that matter all of the rest of the list, deallocated if 
you remove an item from a list.  However, in my example above, the 
Object_Ref type is declared as limited.  What if we had true limited 
access types?

type Pointer is limited access Object;

For such a type deallocating the designated memory when the Pointer 
object goes away would make sense.  I just don't think it is a necessary 
language extension since it is so easy to create the abstraction when 
needed.  (And besides, there are many cases where you want the type to 
appear limited to users, but where you actually want to do assignment in 
the package body.)

-- 
                                           Robert I. Eachus

100% Ada, no bugs--the only way to create software.




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

* Re: Question about OO programming in Ada
  2003-12-04 21:32                                   ` Robert I. Eachus
@ 2003-12-05  8:43                                     ` Dmitry A. Kazakov
  0 siblings, 0 replies; 109+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-05  8:43 UTC (permalink / raw)


On Thu, 04 Dec 2003 16:32:17 -0500, "Robert I. Eachus"
<rieachus@comcast.net> wrote:

>Dmitry A. Kazakov wrote:
>> On Wed, 03 Dec 2003 20:23:53 -0500, "Robert I. Eachus"
>> <rieachus@comcast.net> wrote:

> >                                                     This would
> > not be necessary if finalization of the type Pointer called
> > deallocator in addition to a call to Finalize.
>
>Think about this for a second, because there is a germ of a good idea 
>here.  For access types for which assignment is valid, such a rule would 
>be a disaster.  For example you don't want the next record in a linked 
>list, and for that matter all of the rest of the list, deallocated if 
>you remove an item from a list.

This actually is an argument against controlled-ness. I see little
sense in taking any actions upon access type finalization. This rule
imposes a non-zero run-time burden with practically zero gain.

>However, in my example above, the 
>Object_Ref type is declared as limited.  What if we had true limited 
>access types?
>
>type Pointer is limited access Object;
>
>For such a type deallocating the designated memory when the Pointer 
>object goes away would make sense.  I just don't think it is a necessary 
>language extension since it is so easy to create the abstraction when 
>needed.  (And besides, there are many cases where you want the type to 
>appear limited to users, but where you actually want to do assignment in 
>the package body.)

I think that a real solution is to provide proper construction /
destruction for *all* types. Should we have it, then the problem could
be reduced to developing constructors / destructor of a given access
type. This would allow a user to create any sort of garbage collection
scheme he wants, instead of forcing compiler vendors to implement more
and more sophisticated constructions.

--
Regards,
Dmitry Kazakov
http://www.dmitry-kazakov.de



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

* Re: Question about OO programming in Ada
  2003-11-25 19:04 Question about OO programming in Ada Ekkehard Morgenstern
                   ` (2 preceding siblings ...)
  2003-11-25 21:48 ` Stephen Leake
@ 2003-12-06  7:48 ` Chad Bremmon
  2003-12-06 13:33   ` Jeff C,
  2003-12-06 22:44   ` Hyman Rosen
  3 siblings, 2 replies; 109+ messages in thread
From: Chad Bremmon @ 2003-12-06  7:48 UTC (permalink / raw)


I miss Ada, and it's been a while, but not that long.

C++ piles a lot of crap, pardon the French into the definition for a 
class.

Somewhere, there is a well documented mapping of UML to Ada95, which is 
really what you're trying to ask for.

Since I'm relatively unemployed right now, if I get resounding request 
for it, I could write an OO primer for Ada95.

I know they're out there, but I haven't seen anyone point you right to 
one.

For now I can tell you these things:

1) class wide types are only valuable for dynamic polymorphism

This means that it MUST be a linked list of classwide variables, and the 
compiler cannot possibly know what the type is going to be.

2) to get OO stuff like inheritance, you must declare your operations 
directly after the tagged type definition

3) whether you pass an access or an in/inout, (Has nothing to do with OO 
really.  Everyone else is right.  Stay away from access types unless you 
need them) depends on what you're doing with the tagged type once it is 
passed in.  If it is further used, and the variable (on the stack) may 
become unsafe, then you have to pass an access type so that when the 
program returns, the procedure can't possibly have kept a pointer to 
something on the stack and tried to use it after the variable has been 
popped off the stack

I know I'm babbling...
Here are key OO features and their associated Ada95 features
1.  Inheritance - tagged types
2.  Encapsulation - private types
3.  Polymorphism - 'Class - also access types
4.  Abstraction - packages

That's my penny and a half about it.

Thanks,
Chad
Ekkehard Morgenstern wrote:
> Hi guys,
> 
> I have a question about object-oriented programming in Ada:
> 
> Do I have to use class-wide types for object-oriented programming, or could
> I use regular access types?
> 
> Like, when I declare a procedure
> 
>     procedure A ( B: in access all T'Class )
> 
> could I use a different method and still get all the benefits of Ada
> object-oriented programming?
> 
> Like, what about:
> 
>     procedure A ( B: in access all T )
> 
> or
> 
>     procedure A ( B: in out T )
> 
> or
> 
>     procedure A ( B: in T )
> 
> Also, if I use access types, should I create new types or declare them
> directly in the procedure/function, and what about the 'all' access
> qualifier, should I create two types of access types (one with 'access' and
> one with 'access all'), or should I declare them directly in the procedure
> and decide individually what kind of access I need?
> 
> I would like to program as cleanly as possible in Ada right from the start,
> so I'd be glad if someone could give me some hints. :-)
> 
> 
> 




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

* Re: Question about OO programming in Ada
  2003-12-06  7:48 ` Chad Bremmon
@ 2003-12-06 13:33   ` Jeff C,
  2003-12-06 22:44   ` Hyman Rosen
  1 sibling, 0 replies; 109+ messages in thread
From: Jeff C, @ 2003-12-06 13:33 UTC (permalink / raw)



"Chad Bremmon" <bremmon@acm.org> wrote in message
news:cMGdnQaqSutsF0yiRTvUqQ@rapidnet.com...
> I miss Ada, and it's been a while, but not that long.
>
> C++ piles a lot of crap, pardon the French into the definition for a
> class.
>
> Somewhere, there is a well documented mapping of UML to Ada95, which is
> really what you're trying to ask for.
>
> Since I'm relatively unemployed right now, if I get resounding request
> for it, I could write an OO primer for Ada95.
>
> I know they're out there, but I haven't seen anyone point you right to
> one.


I have not seen any publically available tutorial type writeups for UML to
Ada 95 mapping. You
are probably correct that they exist so I certainly would be interested in
seeing what you can come up
with in your "spare" time.





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

* Re: Question about OO programming in Ada
  2003-12-06  7:48 ` Chad Bremmon
  2003-12-06 13:33   ` Jeff C,
@ 2003-12-06 22:44   ` Hyman Rosen
  2003-12-07  3:02     ` Chad Bremmon
  1 sibling, 1 reply; 109+ messages in thread
From: Hyman Rosen @ 2003-12-06 22:44 UTC (permalink / raw)


Chad Bremmon wrote:
> C++ piles a lot of crap, pardon the French into the definition for a class.

That's because C++ classes do double duty, also acting in
the role that Ada packages fulfill.




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

* Re: Question about OO programming in Ada
  2003-12-06 22:44   ` Hyman Rosen
@ 2003-12-07  3:02     ` Chad Bremmon
  2003-12-07  7:53       ` Hyman Rosen
  0 siblings, 1 reply; 109+ messages in thread
From: Chad Bremmon @ 2003-12-07  3:02 UTC (permalink / raw)


I understand that.  My point is that if you only want encapsulation, 
you have to use a class in C++...with all of the overhead.  In ada, you 
just use a private type.  You don't even need it to be tagged.

To do things that Ada 83 did, you need to use classes in C++. 
Encapsulation, Information hiding, etc, were all things supported in Ada83.


Hyman Rosen wrote:

> Chad Bremmon wrote:
> 
>> C++ piles a lot of crap, pardon the French into the definition for a 
>> class.
> 
> 
> That's because C++ classes do double duty, also acting in
> the role that Ada packages fulfill.
> 




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

* Re: Question about OO programming in Ada
  2003-12-07  3:02     ` Chad Bremmon
@ 2003-12-07  7:53       ` Hyman Rosen
  2003-12-07 15:34         ` James Rogers
  2003-12-07 17:39         ` Chad Bremmon
  0 siblings, 2 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-12-07  7:53 UTC (permalink / raw)


Chad Bremmon wrote:
> I understand that.  My point is that if you only want encapsulation, you 
> have to use a class in C++...with all of the overhead.  In ada, you just 
> use a private type.  You don't even need it to be tagged.

I don't think you do understand. For one, there is no "overhead" whatsoever
in using a class for encapsulation. And in C++ a type may be the equivalent
of tagged or not tagged, as you choose.




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

* Re: Question about OO programming in Ada
  2003-12-07  7:53       ` Hyman Rosen
@ 2003-12-07 15:34         ` James Rogers
  2003-12-07 18:30           ` Martin Krischik
                             ` (2 more replies)
  2003-12-07 17:39         ` Chad Bremmon
  1 sibling, 3 replies; 109+ messages in thread
From: James Rogers @ 2003-12-07 15:34 UTC (permalink / raw)


Hyman Rosen <hyrosen@mail.com> wrote in
news:l0BAb.601$kz2.183@nwrdny01.gnilink.net: 

> I don't think you do understand. For one, there is no "overhead"
> whatsoever in using a class for encapsulation. And in C++ a type may
> be the equivalent of tagged or not tagged, as you choose.

Do you mean to say there is an equivalent of an un-tagged type for
C++ classes? Is this also equivalent to a Java "final" class?

How would you create a C++ equivalent of a ranged integer type that
is also not the equivalent of an Ada tagged type?

Is this done using templates? Templates do incur an overhead. The
overhead is incurred at compile time rather than at run time, but
there is still an overhead.

While speaking of C++ templates, I am amazed at the power and limitations
of C++ templates. The language for C++ templates appears to me to be
an additional syntax beyond the C++ run time syntax. I was surprised to
learn that C++ does not provide for floating point template parameters.
This makes it impossible to provide a template for a ranged real type
in C++.

Jim Rogers



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

* Re: Question about OO programming in Ada
  2003-12-07  7:53       ` Hyman Rosen
  2003-12-07 15:34         ` James Rogers
@ 2003-12-07 17:39         ` Chad Bremmon
  2003-12-08 23:39           ` Hyman Rosen
  2003-12-08 23:40           ` Hyman Rosen
  1 sibling, 2 replies; 109+ messages in thread
From: Chad Bremmon @ 2003-12-07 17:39 UTC (permalink / raw)


Nobody complained when I write this article...disagreeing with an 
article that complained there was too much Overhead in OO in General.

http://www.embedded.com/2000/0010/0010feat2.htm

He was improperly using OO.  There are times when you only want to use a 
"part" of what Object oriented is.

http://www.embedded.com/1999/9908/9908feat1.htm

If you are using a class for encapsulation with C++, the following must 
happen.

1.  For every method call on the class, there is a pointer passed. We 
must explicitly do this in Ada95 (Usually "This" Parameter)if we want 
Object Oriented Programming.

Thanks,
Chad

Hyman Rosen wrote:
> Chad Bremmon wrote:
> 
>> I understand that.  My point is that if you only want encapsulation, 
>> you have to use a class in C++...with all of the overhead.  In ada, 
>> you just use a private type.  You don't even need it to be tagged.
> 
> 
> I don't think you do understand. For one, there is no "overhead" whatsoever
> in using a class for encapsulation. And in C++ a type may be the equivalent
> of tagged or not tagged, as you choose.
> 




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

* Re: Question about OO programming in Ada
  2003-12-07 15:34         ` James Rogers
@ 2003-12-07 18:30           ` Martin Krischik
  2003-12-07 20:25             ` James Rogers
  2003-12-07 21:29           ` Peter C. Chapin
  2003-12-08  3:46           ` Hyman Rosen
  2 siblings, 1 reply; 109+ messages in thread
From: Martin Krischik @ 2003-12-07 18:30 UTC (permalink / raw)


James Rogers wrote:

> Hyman Rosen <hyrosen@mail.com> wrote in
> news:l0BAb.601$kz2.183@nwrdny01.gnilink.net:
> 
>> I don't think you do understand. For one, there is no "overhead"
>> whatsoever in using a class for encapsulation. And in C++ a type may
>> be the equivalent of tagged or not tagged, as you choose.
> 
> Do you mean to say there is an equivalent of an un-tagged type for
> C++ classes? Is this also equivalent to a Java "final" class?

Yes. However there is no keyword for it - just a rule: don't add the
"virtual" keyword.
 
With Regards

Martin
-- 
mailto://krischik@users.sourceforge.net
http://adacl.sourceforge.net




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

* Re: Question about OO programming in Ada
  2003-12-07 18:30           ` Martin Krischik
@ 2003-12-07 20:25             ` James Rogers
  2003-12-08  3:36               ` Hyman Rosen
  0 siblings, 1 reply; 109+ messages in thread
From: James Rogers @ 2003-12-07 20:25 UTC (permalink / raw)


Martin Krischik <krischik@users.sourceforge.net> wrote in 
news:1273941.m4G3ZzughP@linux1.krischik.com:

> James Rogers wrote:
> 
>> Hyman Rosen <hyrosen@mail.com> wrote in
>> news:l0BAb.601$kz2.183@nwrdny01.gnilink.net:
>> 
>>> I don't think you do understand. For one, there is no "overhead"
>>> whatsoever in using a class for encapsulation. And in C++ a type may
>>> be the equivalent of tagged or not tagged, as you choose.
>> 
>> Do you mean to say there is an equivalent of an un-tagged type for
>> C++ classes? Is this also equivalent to a Java "final" class?
> 
> Yes. However there is no keyword for it - just a rule: don't add the
> "virtual" keyword.

I understood "virtual" is a modifier for C++ functions. A C++ class
with non-virtual functions can still be extended with new data members,
or even with new virtual function members. Please correct me if I am 
wrong.

Jim Rogers



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

* Re: Question about OO programming in Ada
  2003-12-07 15:34         ` James Rogers
  2003-12-07 18:30           ` Martin Krischik
@ 2003-12-07 21:29           ` Peter C. Chapin
  2003-12-08  3:44             ` Hyman Rosen
  2003-12-08  3:46           ` Hyman Rosen
  2 siblings, 1 reply; 109+ messages in thread
From: Peter C. Chapin @ 2003-12-07 21:29 UTC (permalink / raw)


In article <Xns944A5737BA540jimmaureenrogers@204.127.36.1>, 
jimmaureenrogers@att.net says...

> While speaking of C++ templates, I am amazed at the power and limitations
> of C++ templates. The language for C++ templates appears to me to be
> an additional syntax beyond the C++ run time syntax. I was surprised to
> learn that C++ does not provide for floating point template parameters.
> This makes it impossible to provide a template for a ranged real type
> in C++.

I believe there is some discussion about lifting the restriction on 
floating point template parameters in the next edition of the C++ 
standard. Of course it remains to be seen if that is done or not.

Peter



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

* Re: Question about OO programming in Ada
  2003-12-07 20:25             ` James Rogers
@ 2003-12-08  3:36               ` Hyman Rosen
  2003-12-08  4:42                 ` Chad Bremmon
  0 siblings, 1 reply; 109+ messages in thread
From: Hyman Rosen @ 2003-12-08  3:36 UTC (permalink / raw)


James Rogers wrote:
> I understood "virtual" is a modifier for C++ functions. A C++ class
> with non-virtual functions can still be extended with new data members,
> or even with new virtual function members. Please correct me if I am 
> wrong.

A C++ class with no virtual functions (of its own or inherited) is the
equivalent of an untagged Ada type. A class with any virtual function
is the equivalent of a tagged type. The typical C++ implementation of
virtual functions (and I imagine the Ada one as well) is to include in
the class a pointer to a dispatch table. While a C++ class has no virtual
functions, the compiler does not place such a dispatch pointer in the
class. When a virtual function is added, the compiler adds the dispatch
pointer.




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

* Re: Question about OO programming in Ada
  2003-12-07 21:29           ` Peter C. Chapin
@ 2003-12-08  3:44             ` Hyman Rosen
  0 siblings, 0 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-12-08  3:44 UTC (permalink / raw)


Peter C. Chapin wrote:
> I believe there is some discussion about lifting the restriction on 
> floating point template parameters in the next edition of the C++ 
> standard. Of course it remains to be seen if that is done or not.

The issue with regards to floating-point template parameters has to do with
C++'s template model. In C++, each use of a template with identical parameters
refers to the same template, unlike Ada, where each instantiation is separate.
Furthermore, template parameters can be (constant) expressions. Thus, allowing
flaoting-point template parameters would have required defining a computational
model for deciding when two instantiations were identical. Instead, the choice
was made to not allow them at all.

For example, given
     template<float f> struct x { static int a; };
     template<float f> int x<f>::a;
     x<1.0> x1;
     x<1.0/2.0 + 1.0/2.0> x2;
     x<1.0/3.0 + 1.0/3.0 + 1.0/3.0> x3;
what can we say about x1::a, x2::a, and x3::a? Do they
all becessarily refer to the same variable. or not?




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

* Re: Question about OO programming in Ada
  2003-12-07 15:34         ` James Rogers
  2003-12-07 18:30           ` Martin Krischik
  2003-12-07 21:29           ` Peter C. Chapin
@ 2003-12-08  3:46           ` Hyman Rosen
  2003-12-08  5:54             ` James Rogers
  2 siblings, 1 reply; 109+ messages in thread
From: Hyman Rosen @ 2003-12-08  3:46 UTC (permalink / raw)


James Rogers wrote:
> Is this done using templates? Templates do incur an overhead. The
> overhead is incurred at compile time rather than at run time, but
> there is still an overhead.

What does it mean to incur a compile-time overhead?

> While speaking of C++ templates, I am amazed at the power and limitations
> of C++ templates. The language for C++ templates appears to me to be
> an additional syntax beyond the C++ run time syntax.

Yes. C++ templates in themselves form a Turing-complete programming
language, executed within the compiler, in functional programming style.




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

* Re: Question about OO programming in Ada
  2003-12-08  3:36               ` Hyman Rosen
@ 2003-12-08  4:42                 ` Chad Bremmon
  2003-12-08  8:42                   ` Hyman Rosen
  0 siblings, 1 reply; 109+ messages in thread
From: Chad Bremmon @ 2003-12-08  4:42 UTC (permalink / raw)




Hyman Rosen wrote:
> James Rogers wrote:
> 
>> I understood "virtual" is a modifier for C++ functions. A C++ class
>> with non-virtual functions can still be extended with new data members,
>> or even with new virtual function members. Please correct me if I am 
>> wrong.
> 
> 
> A C++ class with no virtual functions (of its own or inherited) is the
> equivalent of an untagged Ada type. A class with any virtual function

Not true.  A C++ Struct is the equivalent of an untagged Ada Type.

The Ada encapsulation mechanism is making that Ada type private.

> is the equivalent of a tagged type. The typical C++ implementation of
> virtual functions (and I imagine the Ada one as well) is to include in

Before a dispatch pointer is needed in Ada95, runtime polymorphism must 
be required.  Otherwise, Ada95 always figures out the binding during 
compilation, because it always knows the type of the variable that is 
being passed to the appropriate function.  To get to having runtime 
polymorphism, you must have a linked list of Tagged_Type'Class elements.

Because Ada 95 is strongly typed, the compiler can figure out at compile 
time which function to call, based on the type.  This ensures that 
dispatching is done during compile time.  You still have the look and 
feel of polymorphism, without the non-deterministic nature of runtime 
dispatching.

> the class a pointer to a dispatch table. While a C++ class has no virtual
> functions, the compiler does not place such a dispatch pointer in the
> class. When a virtual function is added, the compiler adds the dispatch
> pointer.
> 




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

* Re: Question about OO programming in Ada
  2003-12-08  3:46           ` Hyman Rosen
@ 2003-12-08  5:54             ` James Rogers
  2003-12-08  8:45               ` Hyman Rosen
  0 siblings, 1 reply; 109+ messages in thread
From: James Rogers @ 2003-12-08  5:54 UTC (permalink / raw)


Hyman Rosen <hyrosen@mail.com> wrote in
news:PuSAb.1600$kz2.1416@nwrdny01.gnilink.net: 

> James Rogers wrote:
>> Is this done using templates? Templates do incur an overhead. The
>> overhead is incurred at compile time rather than at run time, but
>> there is still an overhead.
> 
> What does it mean to incur a compile-time overhead?

The computations are performed at compile time. The casually
observed overhead is a longer compile time.

My point was that any computations done using the C++ template
language require some computation resources by the computer.
No computations happen without associated CPU cycles. On the
other hand, a computation done at compile time is done once.
A computation done at run-time is done each time the code
block containing the computation is executed. This makes the
use of templates very efficient, but not free.

Jim Rogers



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

* Re: Question about OO programming in Ada
  2003-12-08  4:42                 ` Chad Bremmon
@ 2003-12-08  8:42                   ` Hyman Rosen
  2003-12-08  9:34                     ` Dmitry A. Kazakov
                                       ` (2 more replies)
  0 siblings, 3 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-12-08  8:42 UTC (permalink / raw)


Chad Bremmon wrote:
> Not true.  A C++ Struct is the equivalent of an untagged Ada Type.

The only difference between "struct" and "class" in C++ is that the
former begins in public mode and the latter in private mode.

> Before a dispatch pointer is needed in Ada95, runtime polymorphism must 
> be required.  Otherwise, Ada95 always figures out the binding during 
> compilation, because it always knows the type of the variable that is 
> being passed to the appropriate function.  To get to having runtime 
> polymorphism, you must have a linked list of Tagged_Type'Class elements.

But Ada has separate compilation. The compiler can't decide that a
tagged type isn't ever going to need virtual dispatch just because
it hasn't seen an example of it yet.

> Because Ada 95 is strongly typed, the compiler can figure out at compile 
> time which function to call, based on the type.  This ensures that 
> dispatching is done during compile time.  You still have the look and 
> feel of polymorphism, without the non-deterministic nature of runtime 
> dispatching.

What makes you think that C++ is any different in this regard?



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

* Re: Question about OO programming in Ada
  2003-12-08  5:54             ` James Rogers
@ 2003-12-08  8:45               ` Hyman Rosen
  0 siblings, 0 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-12-08  8:45 UTC (permalink / raw)


James Rogers wrote:
> My point was that any computations done using the C++ template
> language require some computation resources by the computer.
> No computations happen without associated CPU cycles. On the
> other hand, a computation done at compile time is done once.
> A computation done at run-time is done each time the code
> block containing the computation is executed. This makes the
> use of templates very efficient, but not free.

The programmers who are writing the templates often get hungry
and have to eat lunch. Don't forget to add that time in as well.



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

* Re: Question about OO programming in Ada
  2003-12-08  8:42                   ` Hyman Rosen
@ 2003-12-08  9:34                     ` Dmitry A. Kazakov
  2003-12-08 13:25                       ` Hyman Rosen
                                         ` (2 more replies)
  2003-12-08 17:27                     ` Chad Bremmon
  2003-12-08 19:25                     ` Martin Krischik
  2 siblings, 3 replies; 109+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-08  9:34 UTC (permalink / raw)


On Mon, 08 Dec 2003 08:42:28 GMT, Hyman Rosen <hyrosen@mail.com>
wrote:

>Chad Bremmon wrote:

>> Because Ada 95 is strongly typed, the compiler can figure out at compile 
>> time which function to call, based on the type.  This ensures that 
>> dispatching is done during compile time.  You still have the look and 
>> feel of polymorphism, without the non-deterministic nature of runtime 
>> dispatching.
>
>What makes you think that C++ is any different in this regard?

C++ does not distinguish class-wide and specific types. The same
object is treated as a class-wide or specific depending on the
run-time call context. For example:

class X 
{
public :
   virtual void Foo ();
   virtual void Baz ()
   {
      Foo ();
   }
   ...

Is the call to Foo from Baz dispatching? The answer is, well,
sometimes it will. Arguably C++ is not strongly typed because no type
could be addressed to implicit "this" in Baz, and so to the actual
type [*).

In Ada one can always statically determine whether a call is
dispatching. Unfortunately, this advantage remains largely unused
because of redispatching support and embedded tags.

-------
[*]  "this" is a class-wide pointer when Baz was not directly or
indirectly called from a constructor/destructor. It is a specific
pointer otherwise.

--
Regards,
Dmitry Kazakov
http://www.dmitry-kazakov.de



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

* Re: Question about OO programming in Ada
  2003-12-08  9:34                     ` Dmitry A. Kazakov
@ 2003-12-08 13:25                       ` Hyman Rosen
  2003-12-08 15:05                         ` Dmitry A. Kazakov
  2003-12-08 17:55                       ` Chad Bremmon
  2003-12-08 19:33                       ` Martin Krischik
  2 siblings, 1 reply; 109+ messages in thread
From: Hyman Rosen @ 2003-12-08 13:25 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> C++ does not distinguish class-wide and specific types.

C++ has no concept of a classwide type as such,
and certainly does not support having objects of
classwide type, that much is true.

> The same object is treated as a class-wide or specific
 > depending on the run-time call context.

Objects declared as a certain type are always treated as
that specific type. Pointers and references to classes are
treated as potential pointers to some derived class. But I
don't think that's what you mean.

> class X 
> {
> public :
>    virtual void Foo ();
>    virtual void Baz () { Foo (); }
>    ...
> 
> Is the call to Foo from Baz dispatching? The answer is, well,
> sometimes it will.
 > [*]  "this" is a class-wide pointer when Baz was not directly or
 > indirectly called from a constructor/destructor. It is a specific
 > pointer otherwise.

No, that is incorrect, showing the level-one misunderstanding of
how this works. (Level-zero is to fail to realize that there's
anything special about this case.)

The call to Foo from Baz is always dispatching, regardless of
whether Baz is called from a *tor or from somewhere else. It is
the dispatch table (or whatever equivalent mechanism the compiler
might use) which changes during *tor execution. The rule is that
while a *tor is executing, the dynamic type of the object is that
type. The "this" pointer is always "classwide", it's the dynamic
type which is changing. As an example, the following prints ABB:
     #include <stdio.h>
     struct A {
         virtual void f() { printf("A"); }
         void g() { f(); }
         A() { g(); }
     };
     struct B : A {
         void f() { printf("B"); }
         B() { g(); }
     };
     int main() { B b; b.g(); }

> Arguably C++ is not strongly typed because no type could be addressed
 > to implicit "this" in Baz, and so to the actual type.

The type of "this" in Baz is (always) pointer-to-X.

> In Ada one can always statically determine whether a call is
> dispatching.

In C++ as well.




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

* Re: Question about OO programming in Ada
  2003-12-08 13:25                       ` Hyman Rosen
@ 2003-12-08 15:05                         ` Dmitry A. Kazakov
  2003-12-09  4:38                           ` Hyman Rosen
  0 siblings, 1 reply; 109+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-08 15:05 UTC (permalink / raw)


On Mon, 08 Dec 2003 08:25:42 -0500, Hyman Rosen <hyrosen@mail.com>
wrote:

>Dmitry A. Kazakov wrote:
>> C++ does not distinguish class-wide and specific types.
>
>C++ has no concept of a classwide type as such,
>and certainly does not support having objects of
>classwide type, that much is true.

Surely it has. No dispatch is possible on specific types. This fact is
language independent.

>> The same object is treated as a class-wide or specific
> > depending on the run-time call context.
>
>Objects declared as a certain type are always treated as
>that specific type. Pointers and references to classes are
>treated as potential pointers to some derived class. But I
>don't think that's what you mean.
>
>> class X 
>> {
>> public :
>>    virtual void Foo ();
>>    virtual void Baz () { Foo (); }
>>    ...
>> 
>> Is the call to Foo from Baz dispatching? The answer is, well,
>> sometimes it will.
> > [*]  "this" is a class-wide pointer when Baz was not directly or
> > indirectly called from a constructor/destructor. It is a specific
> > pointer otherwise.
>
>No, that is incorrect, showing the level-one misunderstanding of
>how this works. (Level-zero is to fail to realize that there's
>anything special about this case.)
>
>The call to Foo from Baz is always dispatching, regardless of
>whether Baz is called from a *tor or from somewhere else. It is
>the dispatch table (or whatever equivalent mechanism the compiler
>might use) which changes during *tor execution.

[..]

The implementation mechanism is irrelevant. Whether given compiler
forges the dispatching table to achieve the effect of making a
dispatching method non-dispatching or "dispatching" as if it were
non-dispatching or whatever you would call it, is no matter. The fact
is, the same method sometimes appears dispatching and sometimes not.

>> Arguably C++ is not strongly typed because no type could be addressed
> > to implicit "this" in Baz, and so to the actual type.
>
>The type of "this" in Baz is (always) pointer-to-X.

See above

>> In Ada one can always statically determine whether a call is
>> dispatching.
>
>In C++ as well.

See above

--
Regards,
Dmitry Kazakov
http://www.dmitry-kazakov.de



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

* Re: Question about OO programming in Ada
  2003-12-08  8:42                   ` Hyman Rosen
  2003-12-08  9:34                     ` Dmitry A. Kazakov
@ 2003-12-08 17:27                     ` Chad Bremmon
  2003-12-08 18:44                       ` Georg Bauhaus
  2003-12-08 23:23                       ` Hyman Rosen
  2003-12-08 19:25                     ` Martin Krischik
  2 siblings, 2 replies; 109+ messages in thread
From: Chad Bremmon @ 2003-12-08 17:27 UTC (permalink / raw)


Hyman Rosen wrote:
> Chad Bremmon wrote:
> 
>> Not true.  A C++ Struct is the equivalent of an untagged Ada Type.
> 
> 
> The only difference between "struct" and "class" in C++ is that the
> former begins in public mode and the latter in private mode.

A class has a parameter associated with it that is always passed to 
every function of that class.  You can't see it.  It's a compiler thing, 
but it's there.

> 
>> Before a dispatch pointer is needed in Ada95, runtime polymorphism 
>> must be required.  Otherwise, Ada95 always figures out the binding 
>> during compilation, because it always knows the type of the variable 
>> that is being passed to the appropriate function.  To get to having 
>> runtime polymorphism, you must have a linked list of Tagged_Type'Class 
>> elements.
> 
> 
> But Ada has separate compilation. The compiler can't decide that a
> tagged type isn't ever going to need virtual dispatch just because
> it hasn't seen an example of it yet.

Yes it can, because if there is supposed to be inheritance, then there 
is a tagged type, which you can inherit from.  I've explained to you how 
difficult it is to create a virtual dispatch at runtime.
> 
>> Because Ada 95 is strongly typed, the compiler can figure out at 
>> compile time which function to call, based on the type.  This ensures 
>> that dispatching is done during compile time.  You still have the look 
>> and feel of polymorphism, without the non-deterministic nature of 
>> runtime dispatching.
> 
> 
> What makes you think that C++ is any different in this regard?

The reason I know what I'm talking about is because I have written 
programs that interface Ada95 and C++, and I know what's happening under 
the covers.  If you would like to take some time to disassemble some C++ 
code and understand what YOU are talking about, feel free.  Until then, 
I'm going to stop arguing with you.  You, my friend, are the one who 
doesn't know what you're talking about.




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

* Re: Question about OO programming in Ada
  2003-12-08  9:34                     ` Dmitry A. Kazakov
  2003-12-08 13:25                       ` Hyman Rosen
@ 2003-12-08 17:55                       ` Chad Bremmon
  2003-12-08 23:09                         ` Hyman Rosen
  2003-12-09  8:26                         ` Dmitry A. Kazakov
  2003-12-08 19:33                       ` Martin Krischik
  2 siblings, 2 replies; 109+ messages in thread
From: Chad Bremmon @ 2003-12-08 17:55 UTC (permalink / raw)




Dmitry A. Kazakov wrote:

> On Mon, 08 Dec 2003 08:42:28 GMT, Hyman Rosen <hyrosen@mail.com>
> wrote:
> 
> 
>>Chad Bremmon wrote:
> 
> 
>>>Because Ada 95 is strongly typed, the compiler can figure out at compile 
>>>time which function to call, based on the type.  This ensures that 
>>>dispatching is done during compile time.  You still have the look and 
>>>feel of polymorphism, without the non-deterministic nature of runtime 
>>>dispatching.
>>
>>What makes you think that C++ is any different in this regard?
> 
> 
> C++ does not distinguish class-wide and specific types. The same
> object is treated as a class-wide or specific depending on the
> run-time call context. For example:
> 
> class X 
> {
> public :
>    virtual void Foo ();
>    virtual void Baz ()
>    {
>       Foo ();
>    }
>    ...
> 
> Is the call to Foo from Baz dispatching? The answer is, well,
> sometimes it will. Arguably C++ is not strongly typed because no type
> could be addressed to implicit "this" in Baz, and so to the actual
> type [*).

This function would NEVER dispatch in Ada95.  Unless the parameter to a 
class is of a Tagged_Type'Class, there is no possibility for dynamic 
runtime dispatcing, period.  End of story. You can't get there!

If you still disagree, code it up and show it to me!

Even if you use the TaggedType'Class as a parameter to a primitive 
operation, the compiler will do it's damndest to get the dispatching 
figured out at compile time.

The above C++ code snipped shows my point.  In C++ you can NEVER know if 
the compiler is going to throw in a dispatching table and another level 
of non-deterministic indirection waiting to get that function called.
> 
> In Ada one can always statically determine whether a call is
> dispatching. Unfortunately, this advantage remains largely unused
> because of redispatching support and embedded tags.
> 
> -------
> [*]  "this" is a class-wide pointer when Baz was not directly or
> indirectly called from a constructor/destructor. It is a specific
> pointer otherwise.
> 
> --
> Regards,
> Dmitry Kazakov
> http://www.dmitry-kazakov.de




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

* Re: Question about OO programming in Ada
  2003-12-08 17:27                     ` Chad Bremmon
@ 2003-12-08 18:44                       ` Georg Bauhaus
  2003-12-08 19:27                         ` Martin Krischik
  2003-12-08 19:36                         ` Chad Bremmon
  2003-12-08 23:23                       ` Hyman Rosen
  1 sibling, 2 replies; 109+ messages in thread
From: Georg Bauhaus @ 2003-12-08 18:44 UTC (permalink / raw)


Chad Bremmon <bremmon@acm.org> wrote:
: Hyman Rosen wrote:
:> Chad Bremmon wrote:
:> 
:>> Not true.  A C++ Struct is the equivalent of an untagged Ada Type.
:> 
:> 
:> The only difference between "struct" and "class" in C++ is that the
:> former begins in public mode and the latter in private mode.
: 
: A class has a parameter associated with it that is always passed to 
: every function of that class.  You can't see it.  It's a compiler thing, 
: but it's there.

What difference does your compiler produce from the following two
files?

testX.cc:

struct X { int a; };

testY.cc:

class Y {public: int a;};


-- Georg




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

* Re: Question about OO programming in Ada
  2003-12-08  8:42                   ` Hyman Rosen
  2003-12-08  9:34                     ` Dmitry A. Kazakov
  2003-12-08 17:27                     ` Chad Bremmon
@ 2003-12-08 19:25                     ` Martin Krischik
  2 siblings, 0 replies; 109+ messages in thread
From: Martin Krischik @ 2003-12-08 19:25 UTC (permalink / raw)


Hyman Rosen wrote:

>> Because Ada 95 is strongly typed, the compiler can figure out at compile
>> time which function to call, based on the type.  This ensures that
>> dispatching is done during compile time.  You still have the look and
>> feel of polymorphism, without the non-deterministic nature of runtime
>> dispatching.
> 
> What makes you think that C++ is any different in this regard?

C++ isn't. However C++ programmers are: they use pointers and references a
lot ;-)

With Regards

Martin

-- 
mailto://krischik@users.sourceforge.net
http://adacl.sourceforge.net




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

* Re: Question about OO programming in Ada
  2003-12-08 18:44                       ` Georg Bauhaus
@ 2003-12-08 19:27                         ` Martin Krischik
  2003-12-08 19:36                         ` Chad Bremmon
  1 sibling, 0 replies; 109+ messages in thread
From: Martin Krischik @ 2003-12-08 19:27 UTC (permalink / raw)


Georg Bauhaus wrote:

> Chad Bremmon <bremmon@acm.org> wrote:
> : Hyman Rosen wrote:
> :> Chad Bremmon wrote:
> :> 
> :>> Not true.  A C++ Struct is the equivalent of an untagged Ada Type.
> :> 
> :> 
> :> The only difference between "struct" and "class" in C++ is that the
> :> former begins in public mode and the latter in private mode.
> : 
> : A class has a parameter associated with it that is always passed to
> : every function of that class.  You can't see it.  It's a compiler thing,
> : but it's there.
> 
> What difference does your compiler produce from the following two
> files?
> 
> testX.cc:
> 
> struct X { int a; };
> 
> testY.cc:
> 
> class Y {public: int a;};

Well, when RTTI is active the stored class names will be different ('X' and
'Y'.) ;-).

With Regards

Martin
-- 
mailto://krischik@users.sourceforge.net
http://adacl.sourceforge.net




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

* Re: Question about OO programming in Ada
  2003-12-08  9:34                     ` Dmitry A. Kazakov
  2003-12-08 13:25                       ` Hyman Rosen
  2003-12-08 17:55                       ` Chad Bremmon
@ 2003-12-08 19:33                       ` Martin Krischik
  2003-12-09  4:41                         ` Hyman Rosen
  2 siblings, 1 reply; 109+ messages in thread
From: Martin Krischik @ 2003-12-08 19:33 UTC (permalink / raw)


Dmitry A. Kazakov wrote:

> On Mon, 08 Dec 2003 08:42:28 GMT, Hyman Rosen <hyrosen@mail.com>
> wrote:
 
> class X
> {
> public :
>    virtual void Foo ();
>    virtual void Baz ()
>    {
>       Foo ();
>    }

> Is the call to Foo from Baz dispatching? The answer is, well,
> sometimes it will.

No, the aswer is yes because you call:

       this->Foo ();

and calls via pointer dispach.

> [*]  "this" is a class-wide pointer when Baz was not directly or
> indirectly called from a constructor/destructor. It is a specific
> pointer otherwise.

This is why one should avoid calling virtual functions in conctructors or
destructors. And if you need to you schould consider making the call non
dispaching: 

X::Foo ();

With Regards

Maritn

-- 
mailto://krischik@users.sourceforge.net
http://adacl.sourceforge.net




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

* Re: Question about OO programming in Ada
  2003-12-08 18:44                       ` Georg Bauhaus
  2003-12-08 19:27                         ` Martin Krischik
@ 2003-12-08 19:36                         ` Chad Bremmon
  2003-12-09  4:43                           ` Hyman Rosen
  1 sibling, 1 reply; 109+ messages in thread
From: Chad Bremmon @ 2003-12-08 19:36 UTC (permalink / raw)




Georg Bauhaus wrote:

> What difference does your compiler produce from the following two
> files?
> 
> testX.cc:
> 
> struct X { int a; };
> 
> testY.cc:
> 
> class Y {public: int a;};

The overhead that I'm referring to doesn't come into play until you call 
a function on a class

The way object oriented programming works, is there is an implicit 
parameter always passed to any function of a C++ class.

It is done explicitly in Ada 95, usually with a this paramter.

Obviously there is no runtime overhead with a declaration, because there 
are no instructions associated with a declaration.  The calls to class 
functions usually involve runtime dispatching in a C++ class, they very 
seldom require dispatching in an Ada95 class.

But, if you're going to just write declarations, there is no overhead, 
becuase it doesn't do anything either way.





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

* Re: Question about OO programming in Ada
  2003-12-08 17:55                       ` Chad Bremmon
@ 2003-12-08 23:09                         ` Hyman Rosen
  2003-12-09  8:26                         ` Dmitry A. Kazakov
  1 sibling, 0 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-12-08 23:09 UTC (permalink / raw)


Chad Bremmon wrote:
 > In C++ you can NEVER know if the compiler is going to throw in a
 > dispatching table and another level of non-deterministic indirection
 > waiting to get that function called.

I'm sorry, but this statement is nonsense. Classes have a dispatching
table if they contain any virtual function. Function calls are dispatching
if made to a virtual function via a pointer or refernce. There is nothing
non-deterministic involved.




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

* Re: Question about OO programming in Ada
  2003-12-08 17:27                     ` Chad Bremmon
  2003-12-08 18:44                       ` Georg Bauhaus
@ 2003-12-08 23:23                       ` Hyman Rosen
  1 sibling, 0 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-12-08 23:23 UTC (permalink / raw)


Chad Bremmon wrote:
> A class has a parameter associated with it that is always passed to 
> every function of that class.  You can't see it.  It's a compiler thing, 
> but it's there.

Rather, ordinary member functions are implemented with a hidden
parameter which is a pointer to the class object, and which becomes
the "this" pointer inside the function. Ada passes the class object
explicitly as a non-hidden parameter. The effect is precisely the
same.

> Yes it can, because if there is supposed to be inheritance, then there 
> is a tagged type, which you can inherit from.  I've explained to you how 
> difficult it is to create a virtual dispatch at runtime.

And I've explained to you that it's the same as in C++, only in
C++ taggedness is implicit rather than explicit.

> The reason I know what I'm talking about is because I have written 
> programs that interface Ada95 and C++, and I know what's happening under 
> the covers.  If you would like to take some time to disassemble some C++ 
> code and understand what YOU are talking about, feel free.  Until then, 
> I'm going to stop arguing with you.  You, my friend, are the one who 
> doesn't know what you're talking about.

I dare say I understand C++ better than some 99.9% of people who
claim to know it (and no, I don't think I'm exaggerating). I think
you're very confused. I would suggest that a good book on C++ would
further your understanding more than disassembling code.

I do recall from old discussions with DK that in Ada you are more
likely to get into situations where you will not redispatch after
having dispatched once, whereas in C++ you will, but I wouldn't
consider that an advantage of Ada.




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

* Re: Question about OO programming in Ada
  2003-12-07 17:39         ` Chad Bremmon
@ 2003-12-08 23:39           ` Hyman Rosen
  2003-12-09  2:36             ` Chad Bremmon
  2003-12-08 23:40           ` Hyman Rosen
  1 sibling, 1 reply; 109+ messages in thread
From: Hyman Rosen @ 2003-12-08 23:39 UTC (permalink / raw)


Chad Bremmon wrote:
> Nobody complained when I write this article...disagreeing with an 
> article that complained there was too much Overhead in OO in General.
> http://www.embedded.com/2000/0010/0010feat2.htm

Well, now that I've read it, how in the world does
     Create(System.Address; Opsys.Unsignedshort)
belong as part of the specification of a Light class?
And what is it about your Ada code that couldn't just
as easily be done in C++?

Oh, and by the way, your sample turn_on and turn_off
functions don't change the state of the Is_On boolean,
so you can never turn a light off once you turn it on!




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

* Re: Question about OO programming in Ada
  2003-12-07 17:39         ` Chad Bremmon
  2003-12-08 23:39           ` Hyman Rosen
@ 2003-12-08 23:40           ` Hyman Rosen
  1 sibling, 0 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-12-08 23:40 UTC (permalink / raw)


Chad Bremmon wrote:
> 1.  For every method call on the class, there is a pointer passed. We 
> must explicitly do this in Ada95 (Usually "This" Parameter)if we want 
> Object Oriented Programming.

Well, yes. Conversely, if you don't want that parameter in C++,
you declare the method to be "static".




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

* Re: Question about OO programming in Ada
  2003-12-08 23:39           ` Hyman Rosen
@ 2003-12-09  2:36             ` Chad Bremmon
  2003-12-09  4:52               ` Hyman Rosen
  2003-12-09 11:24               ` Georg Bauhaus
  0 siblings, 2 replies; 109+ messages in thread
From: Chad Bremmon @ 2003-12-09  2:36 UTC (permalink / raw)


The state of the boolean is not kept in a variable.  The code I wrote 
actually changes the register to turn the light on and off.  A boolean 
is not necessary to keep track of the light.  Either the damn light is 
on or off.

You can tell by looking at the LED.  Is_On is a function to check the 
state of the register in question.

Enough... We're in the team ada room.  I have been explaining how Ada 
works.  I don't particularly care how C++ works.

Chad

Hyman Rosen wrote:
> Chad Bremmon wrote:
> 
>> Nobody complained when I write this article...disagreeing with an 
>> article that complained there was too much Overhead in OO in General.
>> http://www.embedded.com/2000/0010/0010feat2.htm
> 
> 
> Well, now that I've read it, how in the world does
>     Create(System.Address; Opsys.Unsignedshort)
> belong as part of the specification of a Light class?
> And what is it about your Ada code that couldn't just
> as easily be done in C++?
> 
> Oh, and by the way, your sample turn_on and turn_off
> functions don't change the state of the Is_On boolean,
> so you can never turn a light off once you turn it on!
> 




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

* Re: Question about OO programming in Ada
  2003-12-08 15:05                         ` Dmitry A. Kazakov
@ 2003-12-09  4:38                           ` Hyman Rosen
  2003-12-09  8:19                             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 109+ messages in thread
From: Hyman Rosen @ 2003-12-09  4:38 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> No dispatch is possible on specific types. This fact is
> language independent.

No dispatch is necessary, but it is certainly possible.
Tagged objects have a dispatch table, and it can be used
even in those cases where the compiler knows the dynamic
type.

> The fact is, the same method sometimes appears dispatching and sometimes not.

No, that is not the fact. The method is always dispatching, it is simply
that the dispatch table used is different at different times.

> See above

I don't think I see what you see. One of us is seeing things.



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

* Re: Question about OO programming in Ada
  2003-12-08 19:33                       ` Martin Krischik
@ 2003-12-09  4:41                         ` Hyman Rosen
  0 siblings, 0 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-12-09  4:41 UTC (permalink / raw)


Martin Krischik wrote:
>>[*]  "this" is a class-wide pointer when Baz was not directly or
>>indirectly called from a constructor/destructor. It is a specific
>>pointer otherwise.
> 
> This is why one should avoid calling virtual functions in conctructors or
> destructors.

No, "this" is *always* a class-wide pointer, whether a constructor/destructor
is currently active or not. But the dynamic type of *this changes through the
coyrse of the construction/destruction process, to the type of the class being
constructed or destructed. But virtual dispatch is always occurring.



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

* Re: Question about OO programming in Ada
  2003-12-08 19:36                         ` Chad Bremmon
@ 2003-12-09  4:43                           ` Hyman Rosen
  0 siblings, 0 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-12-09  4:43 UTC (permalink / raw)


Chad Bremmon wrote:
> The overhead that I'm referring to doesn't come into play until you call 
> a function on a class
> 
> The way object oriented programming works, is there is an implicit 
> parameter always passed to any function of a C++ class.
> 
> It is done explicitly in Ada 95, usually with a this paramter.

Are you trying to say that the implicit parameter in C++ is somehow
less efficient than the explicit parameter of Ada? Why would you think
such a thing?



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

* Re: Question about OO programming in Ada
  2003-12-09  2:36             ` Chad Bremmon
@ 2003-12-09  4:52               ` Hyman Rosen
  2003-12-09 11:24               ` Georg Bauhaus
  1 sibling, 0 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-12-09  4:52 UTC (permalink / raw)


Chad Bremmon wrote:
> The state of the boolean is not kept in a variable.  The code I wrote 
> actually changes the register to turn the light on and off.  A boolean 
> is not necessary to keep track of the light.  Either the damn light is 
> on or off.

I quote from your article:

     type Object is tagged record
           Address : System.Address;
           Mask    : Opsys.Unsignedshort;
           Is_On   : Boolean := False;
         end record;

     procedure Turn_Off (This : in out Object) is
         Register : Opsys.Unsignedshort;
         for Register'Address use This.Address;
     begin
         if This.Is_On then
             Register := Register xor This.Mask;
         end if;
     end Turn_Off;
     procedure Turn_On (This : in out Object) is
         Register : Opsys.Unsignedshort;
         for Register'Address use This.Address;
     begin
         if not This.Is_On then
             Register := Register xor This.Mask;
         end if;
     end Turn_On;

What changes Is_On?



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

* Re: Question about OO programming in Ada
  2003-12-09  4:38                           ` Hyman Rosen
@ 2003-12-09  8:19                             ` Dmitry A. Kazakov
  2003-12-09 13:29                               ` Hyman Rosen
  0 siblings, 1 reply; 109+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-09  8:19 UTC (permalink / raw)


On Tue, 09 Dec 2003 04:38:25 GMT, Hyman Rosen <hyrosen@mail.com>
wrote:

>Dmitry A. Kazakov wrote:
>> No dispatch is possible on specific types. This fact is
>> language independent.
>
>No dispatch is necessary, but it is certainly possible.
>Tagged objects have a dispatch table, and it can be used
>even in those cases where the compiler knows the dynamic
>type.

Dispatch table is a property of a dispatching subroutine.

>> The fact is, the same method sometimes appears dispatching and sometimes not.
>
>No, that is not the fact. The method is always dispatching, it is simply
>that the dispatch table used is different at different times.

It is a complementary view. Either we say that the type of an object
is mutating or that the type of a formal parameter does (= changing
the dispatch table = changing the subroutine parameter profile). The
effect is same. It is no more strongly typed.

--
Regards,
Dmitry Kazakov
http://www.dmitry-kazakov.de



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

* Re: Question about OO programming in Ada
  2003-12-08 17:55                       ` Chad Bremmon
  2003-12-08 23:09                         ` Hyman Rosen
@ 2003-12-09  8:26                         ` Dmitry A. Kazakov
  1 sibling, 0 replies; 109+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-09  8:26 UTC (permalink / raw)


On Mon, 08 Dec 2003 11:55:02 -0600, Chad Bremmon <bremmon@acm.org>
wrote:

>Dmitry A. Kazakov wrote:
>
>> On Mon, 08 Dec 2003 08:42:28 GMT, Hyman Rosen <hyrosen@mail.com>
>> wrote:
>>  
>>>Chad Bremmon wrote:
>> 
>>>>Because Ada 95 is strongly typed, the compiler can figure out at compile 
>>>>time which function to call, based on the type.  This ensures that 
>>>>dispatching is done during compile time.  You still have the look and 
>>>>feel of polymorphism, without the non-deterministic nature of runtime 
>>>>dispatching.
>>>
>>>What makes you think that C++ is any different in this regard?
>> 
>> C++ does not distinguish class-wide and specific types. The same
>> object is treated as a class-wide or specific depending on the
>> run-time call context. For example:
>> 
>> class X 
>> {
>> public :
>>    virtual void Foo ();
>>    virtual void Baz ()
>>    {
>>       Foo ();
>>    }
>>    ...
>> 
>> Is the call to Foo from Baz dispatching? The answer is, well,
>> sometimes it will. Arguably C++ is not strongly typed because no type
>> could be addressed to implicit "this" in Baz, and so to the actual
>> type [*).
>
>This function would NEVER dispatch in Ada95.  Unless the parameter to a 
>class is of a Tagged_Type'Class, there is no possibility for dynamic 
>runtime dispatcing, period.  End of story. You can't get there!
>
>If you still disagree, code it up and show it to me!

Alas, you are wrong. Ada 95 supports redispatch. It means that you
can:

procedure Baz (X : in out Object) is
begin
   Foo (X'Class (Object)); -- This redispatches
end Baz;

IMO it is a breach of the concept which has to be closed. In rare
cases when redispatch is actually needed Rosen trick would do the
work.

--
Regards,
Dmitry Kazakov
http://www.dmitry-kazakov.de



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

* Re: Question about OO programming in Ada
  2003-12-09  2:36             ` Chad Bremmon
  2003-12-09  4:52               ` Hyman Rosen
@ 2003-12-09 11:24               ` Georg Bauhaus
  2003-12-09 18:42                 ` Chad Bremmon
  1 sibling, 1 reply; 109+ messages in thread
From: Georg Bauhaus @ 2003-12-09 11:24 UTC (permalink / raw)


Chad Bremmon <bremmon@acm.org> wrote:
: The state of the boolean is not kept in a variable.  The code I wrote 
: actually changes the register to turn the light on and off.  A boolean 
: is not necessary to keep track of the light.  Either the damn light is 
: on or off.

Though, if you are the maintainer of a program and see a record
with a boolean component that is never used, how do you, as a
maintainer of readable code, decide what the boolean is about?
All the more when the Boolean, by its name, is obviously related
to subprograms with similar names and "matching" parameter profile?
And then you learn that the author says, the Boolean is unnecessary?
(And this has nothing whatsoever to do with C++ or Ada, does it?)

I would have enjoyed the article more if it had stuck to
the interesting and clear explanation of why O-O is useful,
and how it is done in Ada.
I could imagine that due to its C++ bashing readers are
less likely to see advantages of Ada that you have depicted.

-- Georg



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

* Re: Question about OO programming in Ada
  2003-12-09  8:19                             ` Dmitry A. Kazakov
@ 2003-12-09 13:29                               ` Hyman Rosen
  2003-12-09 14:36                                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 109+ messages in thread
From: Hyman Rosen @ 2003-12-09 13:29 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> Dispatch table is a property of a dispatching subroutine.

No it's not, at least not in the nearly universal C++ implementation.
In that approach, there exists one dispatch table per tagged class
with slots for each virtual function of that class. Then every object
of that class contains a pointer to this single dispatch table. To
make a dispatching call, the compiler accesses the dispatch table
using the index corresponding to the function being called, and calls
the method found there. (The model is more complicated due to virtual
and multiple inheritance, so that an object may contain pointers to
more than one dispatch table, and the addresses are sometimes to fixup
thunks, but that doesn't matter here.)

I'm pretty sure that at least GNAT implements Ada dispatching the
same way.

> It is a complementary view. Either we say that the type of an object
> is mutating or that the type of a formal parameter does (= changing
> the dispatch table = changing the subroutine parameter profile). The
> effect is same. It is no more strongly typed.

In C++, the type of 'this' in a method is always 'pointer-to-class-type-
of-this-method', or a const variant of that. The (dynamic) type of the
object pointed to by 'this' can change as control passes through *tors.
Note that for typical C++ implementations we are not just "saying" that
the type of the object changes; the generated code actually modifies the
dispatch table pointer stored within the object as it progresses through
its construction and destruction. (In fact, I believe Microsoft's C++
compiler offers an option to disable this for efficiency when you can
assure it that it won't matter.)




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

* Re: Question about OO programming in Ada
  2003-12-09 13:29                               ` Hyman Rosen
@ 2003-12-09 14:36                                 ` Dmitry A. Kazakov
  2003-12-09 15:05                                   ` Hyman Rosen
  0 siblings, 1 reply; 109+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-09 14:36 UTC (permalink / raw)


On Tue, 09 Dec 2003 08:29:16 -0500, Hyman Rosen <hyrosen@mail.com>
wrote:

>Dmitry A. Kazakov wrote:
>> Dispatch table is a property of a dispatching subroutine.
>
>No it's not, at least not in the nearly universal C++ implementation.
>In that approach, there exists one dispatch table per tagged class
>with slots for each virtual function of that class. Then every object
>of that class contains a pointer to this single dispatch table. To
>make a dispatching call, the compiler accesses the dispatch table
>using the index corresponding to the function being called, and calls
>the method found there. (The model is more complicated due to virtual
>and multiple inheritance, so that an object may contain pointers to
>more than one dispatch table, and the addresses are sometimes to fixup
>thunks, but that doesn't matter here.)
>
>I'm pretty sure that at least GNAT implements Ada dispatching the
>same way.

Again, implementation issue is irrelevant. It is a subroutine that is
dispatching [in a parameter]. The object is not. The difference
becomes especially clear, when you consider multiple dispatch.

>> It is a complementary view. Either we say that the type of an object
>> is mutating or that the type of a formal parameter does (= changing
>> the dispatch table = changing the subroutine parameter profile). The
>> effect is same. It is no more strongly typed.
>
>In C++, the type of 'this' in a method is always 'pointer-to-class-type-
>of-this-method', or a const variant of that. The (dynamic) type of the
>object pointed to by 'this' can change as control passes through *tors.

This is exaclty what I meant by claiming that it is not a class-wide
pointer. A dispatching subroutine is defined on the whole class
(=closure of the domains of all derived types). Each override
represents a part of its body called according to the type tag. The
behaviour in C++ constructors/destructors clearly violates this. So
either the type is not class-wide or the subroutine is not
dispatching. Choose what you want, the result is same.

>Note that for typical C++ implementations we are not just "saying" that
>the type of the object changes; the generated code actually modifies the
>dispatch table pointer stored within the object as it progresses through
>its construction and destruction. (In fact, I believe Microsoft's C++
>compiler offers an option to disable this for efficiency when you can
>assure it that it won't matter.)

--
Regards,
Dmitry Kazakov
http://www.dmitry-kazakov.de



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

* Re: Question about OO programming in Ada
  2003-12-09 14:36                                 ` Dmitry A. Kazakov
@ 2003-12-09 15:05                                   ` Hyman Rosen
  2003-12-09 15:59                                     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 109+ messages in thread
From: Hyman Rosen @ 2003-12-09 15:05 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> Again, implementation issue is irrelevant. It is a subroutine that is
> dispatching [in a parameter]. The object is not. The difference
> becomes especially clear, when you consider multiple dispatch.

But the common OO languages don't support multiple dispatch,
and whether or not you regard implementation as irrelevant,
it is nevertheless the case that dispatching in those languages
is coordinated around the object type, not separately around each
dispatching function.

> This is exaclty what I meant by claiming that it is not a class-wide
> pointer. A dispatching subroutine is defined on the whole class
> (=closure of the domains of all derived types). Each override
> represents a part of its body called according to the type tag. The
> behaviour in C++ constructors/destructors clearly violates this. So
> either the type is not class-wide or the subroutine is not
> dispatching. Choose what you want, the result is same.

You either-or is a false dichotomy. As you say, "Each override
represents a part of its body called according to the type tag."
In C++, the type tag stored within the object changes as the code
progresses through constructors and destructors. Didn't I post this
sample code already?

     #include <stdio.h>
     struct A
     {
         virtual void f() { printf("A"); }
         void g() { f(); } // This call is always dispatching
         A() { g(); }
     }
     struct B : A
     {
         void f() { printf("B"); } // overrides A::f
         B() { g(); }
     }
     int main() { B b; b.g(); }

This code prints "ABB". In A::g, the type of 'this' is 'pointer-to-A'.
The dynamic type of '*this' is A when called from A's constructor and
B when called from B's constructor, because the compiler is updating
the tag within the object as its construction progresses. The call to
f in A::g always dispatches using the dynamic type of '*this'.




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

* Re: Question about OO programming in Ada
  2003-12-09 15:05                                   ` Hyman Rosen
@ 2003-12-09 15:59                                     ` Dmitry A. Kazakov
  2003-12-09 16:41                                       ` Hyman Rosen
  0 siblings, 1 reply; 109+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-09 15:59 UTC (permalink / raw)


On Tue, 09 Dec 2003 10:05:07 -0500, Hyman Rosen <hyrosen@mail.com>
wrote:

>Dmitry A. Kazakov wrote:
>> Again, implementation issue is irrelevant. It is a subroutine that is
>> dispatching [in a parameter]. The object is not. The difference
>> becomes especially clear, when you consider multiple dispatch.
>
>But the common OO languages don't support multiple dispatch,
>and whether or not you regard implementation as irrelevant,
>it is nevertheless the case that dispatching in those languages
>is coordinated around the object type, not separately around each
>dispatching function.

So what?

>> This is exaclty what I meant by claiming that it is not a class-wide
>> pointer. A dispatching subroutine is defined on the whole class
>> (=closure of the domains of all derived types). Each override
>> represents a part of its body called according to the type tag. The
>> behaviour in C++ constructors/destructors clearly violates this. So
>> either the type is not class-wide or the subroutine is not
>> dispatching. Choose what you want, the result is same.
>
>You either-or is a false dichotomy. As you say, "Each override
>represents a part of its body called according to the type tag."
>In C++, the type tag stored within the object changes as the code
>progresses through constructors and destructors.

If the type tag gets changed, then the type does as well. End of
story.

For an object of *same* type a dispatch to *same* method should yeld
same target. It is not the case for C++. The target in constructor /
destructor or their callee is same as if the method were not
dispatching. So I claim again, if it "dispatches" as a type-specific
call, then it is type specific.

--
Regards,
Dmitry Kazakov
http://www.dmitry-kazakov.de



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

* Re: Question about OO programming in Ada
  2003-12-09 15:59                                     ` Dmitry A. Kazakov
@ 2003-12-09 16:41                                       ` Hyman Rosen
  2003-12-10 11:32                                         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 109+ messages in thread
From: Hyman Rosen @ 2003-12-09 16:41 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> So what?

So it's somewhat iconoclastic to regard the function as
the focus of the dispatching. You're doing it because you
are still pushing for your external fat-pointer dispatch
mechanism, which is why you decry the ability to redispatch.

I rememeber the old discussion, but people who don't aren't
going to understand what you're fussing about, since the
dispatch table implementation mechanism is fixed in many
minds as the very definition of OO.

> If the type tag gets changed, then the type does as well.

Yes, absolutely.

> For an object of *same* type a dispatch to *same* method
 > should yeld same target.

Yes, absolutely.

> It is not the case for C++.

No, that's wrong. It *is* the case for C++.

> The target in constructor / destructor or their callee is same
 > as if the method were not dispatching.

No, that's wrong as well. Did you look at my sample code?
Calls to virtual functions are always dispatching. The type
used to dispatch upon may vary during the course of construction.

> So I claim again, if it "dispatches" as a type-specific
> call, then it is type specific.

I don't understand what this sentence means.




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

* Re: Question about OO programming in Ada
  2003-12-09 11:24               ` Georg Bauhaus
@ 2003-12-09 18:42                 ` Chad Bremmon
  2003-12-09 20:11                   ` Hyman Rosen
  0 siblings, 1 reply; 109+ messages in thread
From: Chad Bremmon @ 2003-12-09 18:42 UTC (permalink / raw)


After looking back, I agree with Hyman's criticism of my code.  I should 
have been setting the variable.

It was actually very difficult to keep in the code what was meaningful 
and delete what wasn't when I was deciding what to stick in the article.

If you go back to the purpose of my article, it was to refute testimony 
that OO programming would NOT work for embedded systems programming at all.

The other guys point was:

"With using C++, I got all of this overhead."

I explained two reasons for his overhead!

1.  The idea of encapsulating a register and calling it a register when 
you get done is pretty stupid.  I went on to explain that if you wanted 
to encapsulate a register that represented a light, then write a light 
class.

2.  C++ has a lot of problems with redispatching, etc.  If you still 
wanted to access a register and encapsulate it, you can't do it without 
using a Class in C++.  We are discussing the "default" behavior of C++ 
here.  You can do a pretty good job of tying down, but open and 
dispatching is the way C++ works out of the box.  In actuality, if you 
wanted to encapsulate a meaningless register, you would want to use a 
variable and set the address for it's location specifically.

Thanks,
Chad


Georg Bauhaus wrote:
> Chad Bremmon <bremmon@acm.org> wrote:
> : The state of the boolean is not kept in a variable.  The code I wrote 
> : actually changes the register to turn the light on and off.  A boolean 
> : is not necessary to keep track of the light.  Either the damn light is 
> : on or off.
> 
> Though, if you are the maintainer of a program and see a record
> with a boolean component that is never used, how do you, as a
> maintainer of readable code, decide what the boolean is about?
> All the more when the Boolean, by its name, is obviously related
> to subprograms with similar names and "matching" parameter profile?
> And then you learn that the author says, the Boolean is unnecessary?
> (And this has nothing whatsoever to do with C++ or Ada, does it?)
> 
> I would have enjoyed the article more if it had stuck to
> the interesting and clear explanation of why O-O is useful,
> and how it is done in Ada.
> I could imagine that due to its C++ bashing readers are
> less likely to see advantages of Ada that you have depicted.
> 
> -- Georg




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

* Re: Question about OO programming in Ada
  2003-12-09 18:42                 ` Chad Bremmon
@ 2003-12-09 20:11                   ` Hyman Rosen
  0 siblings, 0 replies; 109+ messages in thread
From: Hyman Rosen @ 2003-12-09 20:11 UTC (permalink / raw)


Chad Bremmon wrote:
 > C++ has a lot of problems with redispatching, etc.

C++ has certain ways in which it does things, but to
characterize them as "problems" is an unwarranted slur.
In your sample Light class, I don't see anything that
isn't completely straightforward and easily written in
C++, in much the same way.

If you don't want redispatch, don't make the implementation
methods virtual. I don't see what the big deal is. Can you
supply sample C++ code which you think causes problems?




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

* Re: Question about OO programming in Ada
  2003-12-09 16:41                                       ` Hyman Rosen
@ 2003-12-10 11:32                                         ` Dmitry A. Kazakov
  2003-12-10 15:27                                           ` Hyman Rosen
  0 siblings, 1 reply; 109+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-10 11:32 UTC (permalink / raw)


On Tue, 09 Dec 2003 11:41:56 -0500, Hyman Rosen <hyrosen@mail.com>
wrote:

>Dmitry A. Kazakov wrote:
>> So what?
>
>So it's somewhat iconoclastic to regard the function as
>the focus of the dispatching. You're doing it because you
>are still pushing for your external fat-pointer dispatch
>mechanism, which is why you decry the ability to redispatch.

No, the reason is that redispatch violates strong typing. If the
contract of a subprogram is that some parameter has a specific type,
then why on earth a call to other subroutine with this parameter
should dispatch? This is C++ design fault which uses same notation for
both class-wide and specific types. Further, if that specific object
is being converted to a class-wide, then why the result is not rooted
in the type specified by the *contract*? This is Ada 95 design fault.
Both faults stems from redispatch, which cannot be implemented in a
type-safe and type-consistent way.

>I rememeber the old discussion, but people who don't aren't
>going to understand what you're fussing about, since the
>dispatch table implementation mechanism is fixed in many
>minds as the very definition of OO.

I don't argue against dispatch tables. My point that a dispatch table
belongs to a subroutine, not to an object. Then OO, as an approach,
has little to do with implementation issues. It only states that there
are dispatching subroutines. Note, subroutines, not "dispatching
objects".

>> If the type tag gets changed, then the type does as well.
>
>Yes, absolutely.
>
>> For an object of *same* type a dispatch to *same* method
> > should yeld same target.
>
>Yes, absolutely.
>
>> It is not the case for C++.
>
>No, that's wrong. It *is* the case for C++.

It is exactly not the case:

class X 
{
public :
   virtual void Foo () { printf ("X::Foo"); }
   virtual void Baz () { Foo (); }
   virtual ~X () { Baz (); }
};

class Y : public X
{
public :
   virtual void Foo () { printf ("Y::Foo"); }
};

void main ()
{
   Y A;

   A.Baz (); // dispatches to Y::Foo

} // Y::~Y does not dispatch to Y::Foo

This should print:

Y::Foo
X::Foo

>> The target in constructor / destructor or their callee is same
> > as if the method were not dispatching.
>
>No, that's wrong as well. Did you look at my sample code?
>Calls to virtual functions are always dispatching. The type
>used to dispatch upon may vary during the course of construction.
>
>> So I claim again, if it "dispatches" as a type-specific
>> call, then it is type specific.
>
>I don't understand what this sentence means.

See my example.

--
Regards,
Dmitry Kazakov
http://www.dmitry-kazakov.de



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

* Re: Question about OO programming in Ada
  2003-12-10 11:32                                         ` Dmitry A. Kazakov
@ 2003-12-10 15:27                                           ` Hyman Rosen
  2003-12-10 17:15                                             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 109+ messages in thread
From: Hyman Rosen @ 2003-12-10 15:27 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> No, the reason is that redispatch violates strong typing. If the
> contract of a subprogram is that some parameter has a specific type

But it's only in your mind that such a contract exists.
Certainly in C++, whenever you have a pointer or reference
to a class object, it is always the case that the pointed-to
object may in fact be of a more derived class. Even in Ada,
don't derived classes inherit the subprograms of their base
class unless those are overridden? Or does Ada act as if the
subprograms had been rewritten line-for-line with the new
type in place of the old one?

Not only that, but objects are often members of other objects.
Your "parameter of a specific type" may be a field of a record,
or a member of an array, or the base part of a derived object.
Redispatching is simply one way of going from the inner object
to the containing one, in much the way access discriminants are
touted here.

> This is C++ design fault which uses same notation for
> both class-wide and specific types.

The designers felt, and I think experience has borne out, that
redispatching behavior is what is wanted and expected. You can
always prevent redispatching, if that's what you want, by saying
     p->SpecificClass::function();

> Both faults stems from redispatch, which cannot be implemented in a
> type-safe and type-consistent way.

Redispatch in C++ seems perfectly consistent and type-safe to me,
since I don't make false or wishful assumptions about what a
declaration means, but rather accept the language's specification
of that. I believe the same is true for Ada.

> I don't argue against dispatch tables. My point that a dispatch table
> belongs to a subroutine, not to an object. Then OO, as an approach,
> has little to do with implementation issues. It only states that there
> are dispatching subroutines. Note, subroutines, not "dispatching
> objects".

That may be your view, but it certainly isn't the ordinary one.
Rather, there are a bunch of unrelated subprograms that happen
to share a name and parameter profile, and a system invokes one
of those subprograms when a dispatching call is made to that
name and parameter profile.

> It is exactly not the case:
> 
> class X 
> {
> public :
>    virtual void Foo () { printf ("X::Foo"); }
>    virtual void Baz () { Foo (); }
>    virtual ~X () { Baz (); }
> };
> 
> class Y : public X
> {
> public :
>    virtual void Foo () { printf ("Y::Foo"); }
> };
> 
> void main ()
> {
>    Y A;
> 
>    A.Baz (); // dispatches to Y::Foo
> 
> } // Y::~Y does not dispatch to Y::Foo
> 
> This should print:
> 
> Y::Foo
> X::Foo

Why did you not also include in Y
     virtual ~Y() { Baz(); }
Then you would see that it prints
     Y::Foo
     Y::Foo
     X::Foo
showing that Y::~Y does first dispatch to Y::Foo.
You left out the case that demonstrates that I am correct.




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

* Re: Question about OO programming in Ada
  2003-12-10 15:27                                           ` Hyman Rosen
@ 2003-12-10 17:15                                             ` Dmitry A. Kazakov
  0 siblings, 0 replies; 109+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-10 17:15 UTC (permalink / raw)


On Wed, 10 Dec 2003 10:27:43 -0500, Hyman Rosen <hyrosen@mail.com>
wrote:

>Dmitry A. Kazakov wrote:
>> No, the reason is that redispatch violates strong typing. If the
>> contract of a subprogram is that some parameter has a specific type
>
>But it's only in your mind that such a contract exists.

No contract no strong typing.

>Certainly in C++, whenever you have a pointer or reference
>to a class object, it is always the case that the pointed-to
>object may in fact be of a more derived class.

It is no problem if held in all contexts. This is the sense of having
a contract.

> Even in Ada,
>don't derived classes inherit the subprograms of their base
>class unless those are overridden? Or does Ada act as if the
>subprograms had been rewritten line-for-line with the new
>type in place of the old one?

This is the whole idea of substitutability.

>Not only that, but objects are often members of other objects.
>Your "parameter of a specific type" may be a field of a record,
>or a member of an array, or the base part of a derived object.
>Redispatching is simply one way of going from the inner object
>to the containing one, in much the way access discriminants are
>touted here.

You are confusing implementation inheritance [by extension] and
aggregation.

>> This is C++ design fault which uses same notation for
>> both class-wide and specific types.
>
>The designers felt, and I think experience has borne out, that
>redispatching behavior is what is wanted and expected. You can
>always prevent redispatching, if that's what you want, by saying
>     p->SpecificClass::function();

Yep, and dispatch can be written using switch statement. It is
Turing-complete anyway.

>> Both faults stems from redispatch, which cannot be implemented in a
>> type-safe and type-consistent way.
>
>Redispatch in C++ seems perfectly consistent and type-safe to me,
>since I don't make false or wishful assumptions about what a
>declaration means, but rather accept the language's specification
>of that. I believe the same is true for Ada.
>
>> I don't argue against dispatch tables. My point that a dispatch table
>> belongs to a subroutine, not to an object. Then OO, as an approach,
>> has little to do with implementation issues. It only states that there
>> are dispatching subroutines. Note, subroutines, not "dispatching
>> objects".
>
>That may be your view, but it certainly isn't the ordinary one.
>Rather, there are a bunch of unrelated subprograms that happen
>to share a name and parameter profile, and a system invokes one
>of those subprograms when a dispatching call is made to that
>name and parameter profile.

Certainly, there is no such thing as int type. There is only a bunch
of unrelated numbers and a system places one or another in a memory
cell according to signs of the zodiac.

>> It is exactly not the case:
>> 
>> class X 
>> {
>> public :
>>    virtual void Foo () { printf ("X::Foo"); }
>>    virtual void Baz () { Foo (); }
>>    virtual ~X () { Baz (); }
>> };
>> 
>> class Y : public X
>> {
>> public :
>>    virtual void Foo () { printf ("Y::Foo"); }
>> };
>> 
>> void main ()
>> {
>>    Y A;
>> 
>>    A.Baz (); // dispatches to Y::Foo
>> 
>> } // Y::~Y does not dispatch to Y::Foo
>> 
>> This should print:
>> 
>> Y::Foo
>> X::Foo
>
>Why did you not also include in Y
>     virtual ~Y() { Baz(); }

Because the above is enough to illustrate the point.

1. If this is a class-wide pointer then Baz() violates its contract
when called from the destructor of Y.

2. If this is a specific pointer then Baz() violates the contract when
called as A.Baz().

From this immediately follows the proposition I started with, "this"
is sometimes class-wide and sometimes specific.

>Then you would see that it prints
>     Y::Foo
>     Y::Foo
>     X::Foo
>showing that Y::~Y does first dispatch to Y::Foo.
>You left out the case that demonstrates that I am correct.

--
Regards,
Dmitry Kazakov
http://www.dmitry-kazakov.de



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

end of thread, other threads:[~2003-12-10 17:15 UTC | newest]

Thread overview: 109+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-11-25 19:04 Question about OO programming in Ada Ekkehard Morgenstern
2003-11-25 20:17 ` Randy Brukardt
2003-11-26  0:34   ` Ekkehard Morgenstern
2003-11-26  6:17     ` Vinzent 'Gadget' Hoefler
2003-11-26  9:29     ` Dmitry A. Kazakov
2003-11-26 15:54     ` Stephen Leake
2003-11-26 20:07       ` Randy Brukardt
2003-11-26 21:36         ` Stephen Leake
2003-11-26  8:56   ` Peter Hermann
2003-11-25 20:55 ` Martin Krischik
2003-11-26  0:22   ` Ekkehard Morgenstern
2003-11-26  1:00     ` Jeffrey Carter
2003-11-26 16:36     ` Martin Krischik
2003-11-26 18:09       ` Robert I. Eachus
2003-11-27 13:45         ` Jean-Pierre Rosen
2003-11-25 21:48 ` Stephen Leake
2003-11-26  0:01   ` Ekkehard Morgenstern
2003-11-26  1:16     ` Jeffrey Carter
2003-11-26 15:10     ` Georg Bauhaus
2003-11-26 15:48     ` Stephen Leake
2003-11-26 16:24       ` Hyman Rosen
2003-11-26 17:58     ` Robert I. Eachus
2003-11-27  2:10       ` Ekkehard Morgenstern
2003-11-27 10:15         ` Ludovic Brenta
2003-11-27 18:35         ` Jeffrey Carter
2003-11-28  4:35           ` Hyman Rosen
2003-11-28  7:28             ` Vinzent 'Gadget' Hoefler
2003-11-28  8:46               ` Dale Stanbrough
2003-11-28 10:16                 ` Vinzent 'Gadget' Hoefler
2003-12-01 15:57             ` Martin Krischik
2003-12-01 16:47               ` Hyman Rosen
2003-12-03 18:35                 ` Martin Krischik
2003-12-01 21:13               ` Jeffrey Carter
2003-12-02  8:47               ` Dmitry A. Kazakov
2003-12-03  9:29                 ` Pascal Obry
2003-12-03 11:26                   ` Dmitry A. Kazakov
2003-12-03 12:49                     ` Ludovic Brenta
2003-12-03 13:41                       ` Dmitry A. Kazakov
2003-12-03 14:11                         ` Ludovic Brenta
2003-12-03 14:45                           ` Dmitry A. Kazakov
2003-12-03 15:44                         ` Hyman Rosen
2003-12-03 16:11                           ` Dmitry A. Kazakov
2003-12-03 18:20                           ` David C. Hoos
     [not found]                           ` <28eb01c3b9ca$25b18870$b101a8c0@sy.com>
2003-12-03 18:35                             ` Hyman Rosen
2003-12-03 20:05                           ` Randy Brukardt
2003-12-03 20:57                             ` Hyman Rosen
2003-12-03 21:16                               ` Hyman Rosen
2003-12-03 22:04                           ` Pascal Obry
2003-12-03 22:34                             ` Hyman Rosen
2003-12-04  1:23                               ` Robert I. Eachus
2003-12-04  7:15                                 ` Hyman Rosen
2003-12-04 17:43                                   ` Warren W. Gay VE3WWG
2003-12-04  8:55                                 ` Dmitry A. Kazakov
2003-12-04 19:13                                   ` Randy Brukardt
2003-12-04 19:29                                     ` Hyman Rosen
2003-12-04 21:32                                   ` Robert I. Eachus
2003-12-05  8:43                                     ` Dmitry A. Kazakov
2003-11-27 22:12         ` Robert I. Eachus
2003-11-28  6:37           ` Simon Wright
2003-11-30  2:51             ` Robert I. Eachus
2003-12-06  7:48 ` Chad Bremmon
2003-12-06 13:33   ` Jeff C,
2003-12-06 22:44   ` Hyman Rosen
2003-12-07  3:02     ` Chad Bremmon
2003-12-07  7:53       ` Hyman Rosen
2003-12-07 15:34         ` James Rogers
2003-12-07 18:30           ` Martin Krischik
2003-12-07 20:25             ` James Rogers
2003-12-08  3:36               ` Hyman Rosen
2003-12-08  4:42                 ` Chad Bremmon
2003-12-08  8:42                   ` Hyman Rosen
2003-12-08  9:34                     ` Dmitry A. Kazakov
2003-12-08 13:25                       ` Hyman Rosen
2003-12-08 15:05                         ` Dmitry A. Kazakov
2003-12-09  4:38                           ` Hyman Rosen
2003-12-09  8:19                             ` Dmitry A. Kazakov
2003-12-09 13:29                               ` Hyman Rosen
2003-12-09 14:36                                 ` Dmitry A. Kazakov
2003-12-09 15:05                                   ` Hyman Rosen
2003-12-09 15:59                                     ` Dmitry A. Kazakov
2003-12-09 16:41                                       ` Hyman Rosen
2003-12-10 11:32                                         ` Dmitry A. Kazakov
2003-12-10 15:27                                           ` Hyman Rosen
2003-12-10 17:15                                             ` Dmitry A. Kazakov
2003-12-08 17:55                       ` Chad Bremmon
2003-12-08 23:09                         ` Hyman Rosen
2003-12-09  8:26                         ` Dmitry A. Kazakov
2003-12-08 19:33                       ` Martin Krischik
2003-12-09  4:41                         ` Hyman Rosen
2003-12-08 17:27                     ` Chad Bremmon
2003-12-08 18:44                       ` Georg Bauhaus
2003-12-08 19:27                         ` Martin Krischik
2003-12-08 19:36                         ` Chad Bremmon
2003-12-09  4:43                           ` Hyman Rosen
2003-12-08 23:23                       ` Hyman Rosen
2003-12-08 19:25                     ` Martin Krischik
2003-12-07 21:29           ` Peter C. Chapin
2003-12-08  3:44             ` Hyman Rosen
2003-12-08  3:46           ` Hyman Rosen
2003-12-08  5:54             ` James Rogers
2003-12-08  8:45               ` Hyman Rosen
2003-12-07 17:39         ` Chad Bremmon
2003-12-08 23:39           ` Hyman Rosen
2003-12-09  2:36             ` Chad Bremmon
2003-12-09  4:52               ` Hyman Rosen
2003-12-09 11:24               ` Georg Bauhaus
2003-12-09 18:42                 ` Chad Bremmon
2003-12-09 20:11                   ` Hyman Rosen
2003-12-08 23:40           ` Hyman Rosen

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