* 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 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: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-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: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: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-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-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 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-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: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 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 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-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-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: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 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: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 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-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 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-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 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 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 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
[parent not found: <28eb01c3b9ca$25b18870$b101a8c0@sy.com>]
* 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 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 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 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-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 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 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-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 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 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-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 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 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 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-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-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 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
* 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: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: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-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 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 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 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 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 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 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-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-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-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 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: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 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-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 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-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-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 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 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-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
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