* Q: Endless loop by dispatching @ 2003-07-11 8:22 Michael Erdmann 2003-07-11 9:46 ` Jean-Pierre Rosen ` (2 more replies) 0 siblings, 3 replies; 35+ messages in thread From: Michael Erdmann @ 2003-07-11 8:22 UTC (permalink / raw) Dear all, i got a problem with the following code fragment below. The Idea is that the procedure Serialize defines the strategy how to display object which are derived from A.Object. Searialize simply dispatches into the class by calling a procedure Write, which does the job for the class. package A is type Object is tagged record P1 : Natural := 1; P2 : Natural := 2; end record; procedure Write( This : in Object ); procedure Serialize( This : in Object'Class ); end A; package body A is procedure Serialize( This : in Object'Class ) is begin Write( This ); end Serialize; procedure Write( This : in Object ) is begin Put_Line( "P1 =" & Natural'Image( This.P1 ) ); Put_Line( "P2 =" & Natural'Image( This.P2 ) ); end Write; end A; In the following fragment i am defining a package B with an derived objec B.Object as below. When an instance of B.Object shall be serialized, the element of the super class (A.Object) shall be serialzed as well. The code looks nice and compiles but does not work, since the Serialize dispatches again with Object.B even ther was a a case given A.Object( This ). package B is type Object is new A.Object with record Q : Natural := 2; end record; procedure Write( This : in Object ); end B; .......... package body B is procedure Write( This : in Object ) is begin A.Serialize( A.Object( This ) ); Put_Line( "Q =" & Natural'Image(This.Q)); end Write; end B; Does any body know, what this loop causes?! I am not sure if this is a bug or simply i missed the point. Michael ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Endless loop by dispatching 2003-07-11 8:22 Q: Endless loop by dispatching Michael Erdmann @ 2003-07-11 9:46 ` Jean-Pierre Rosen 2003-07-11 15:19 ` Michael Erdmann 2003-07-11 10:01 ` Q: " Dmitry A. Kazakov 2003-07-11 16:27 ` T. Kurt Bond 2 siblings, 1 reply; 35+ messages in thread From: Jean-Pierre Rosen @ 2003-07-11 9:46 UTC (permalink / raw) [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain, Size: 1033 bytes --] "Michael Erdmann" <michael.erdmann@snafu.de> a �crit dans le message de news:un82u-4kb.ln1@boavista.snafu.de... [SNIP] > Does any body know, what this loop causes?! I am not sure > if this is a bug or simply i missed the point. > You missed the point :-) Serialize is a general entry point, which dispatches to Write. If you call it again from Write, it will redispatch to Write, hence the loop. Now do you think that Write of B is really Serialize of A, plus something else? Isn't it *Write* of A, plus something else? If you change your package to package body B is procedure Write( This : in Object ) is begin A.Write( A.Object( This ) ); Put_Line( "Q =" & Natural'Image(This.Q)); end Write; end B; It will be OK. Oh, by the way, why do you need Serialize at all? Since all it does is call Write, why don't you call Write directly? -- --------------------------------------------------------- J-P. Rosen (rosen@adalog.fr) Visit Adalog's web site at http://www.adalog.fr ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Endless loop by dispatching 2003-07-11 9:46 ` Jean-Pierre Rosen @ 2003-07-11 15:19 ` Michael Erdmann 0 siblings, 0 replies; 35+ messages in thread From: Michael Erdmann @ 2003-07-11 15:19 UTC (permalink / raw) To: Jean-Pierre Rosen Jean-Pierre Rosen wrote: > > You missed the point :-) > I understood this mean while. It seems that the case A.Object(This) does not change the tag. I have checked the RM but i found nothing, but this seems to be accepted as normal behaviour in the community. > Serialize is a general entry point, which dispatches to Write. If you call it again from Write, it will redispatch > to Write, hence the loop. > > Now do you think that Write of B is really Serialize of A, plus something else? > Isn't it *Write* of A, plus something else? If you change your package to > > package body B is > > procedure Write( > This : in Object ) is > begin > A.Write( A.Object( This ) ); > Put_Line( "Q =" & Natural'Image(This.Q)); > end Write; > > end B; > > It will be OK. > > Oh, by the way, why do you need Serialize at all? Since all it does is call Write, why don't you > call Write directly? > Maybe the conseded code i have sent was missleading. Since the procedure Serialize is intended to do more then just i put it here as pseudocode: procedure Serialze( this : in Object'Class ) is Serialize( Super( This ) ); F := Get( Attribute( this'Tag ) ) while F /= null loop Unbounded_String'Output( S, F.Name ); Write( This, F.Id ); F := Next(...); end loop; end Serialize: Using write directly is possible but then i have to put the code of serialze everwhere were i want to do the trick. I there would be something like the Super operation yielding the references to the super class then everthing would be fine, i guess! Michael ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-11 8:22 Q: Endless loop by dispatching Michael Erdmann 2003-07-11 9:46 ` Jean-Pierre Rosen @ 2003-07-11 10:01 ` Dmitry A. Kazakov 2003-07-11 15:07 ` Michael Erdmann 2003-07-11 16:27 ` T. Kurt Bond 2 siblings, 1 reply; 35+ messages in thread From: Dmitry A. Kazakov @ 2003-07-11 10:01 UTC (permalink / raw) On Fri, 11 Jul 2003 10:22:54 +0200, Michael Erdmann <michael.erdmann@snafu.de> wrote: >i got a problem with the following code fragment below. The Idea is that >the procedure Serialize defines the strategy how to display object which >are derived from A.Object. Searialize simply dispatches into the class >by calling a procedure Write, which does the job for the class. [...] >In the following fragment i am defining a package B with an >derived objec B.Object as below. When an instance of B.Object >shall be serialized, the element of the super class (A.Object) >shall be serialzed as well. The code looks nice and compiles >but does not work, since the Serialize dispatches again with >Object.B even ther was a a case given A.Object( This ). [...] >Does any body know, what this loop causes?! I am not sure >if this is a bug or simply i missed the point. Serialize is class-wide and a view conversion does not change the tag..I.e. you have a re-dispatching case. Re-dispatching is a dangerous thing. [I would like it removed from Ada] So Serialize re-dispatches to B.Write which again calls Serialize. From design point of view, one should never call class-wide routines from specific ones, this warranties that dispatch happens only once. I suppose that you want sort of procedure expansion instead of complete overriding, if so, then you should explicitly call parent's Write, similarly as one does it for Initialize/Finalize: package body B is ... procedure Write (This : in Object) is begin -- A.Serialize( A.Object( This ) ); A.Write (A.Object (This)); -- Write parent's things Put_Line( "Q =" & Natural'Image(This.Q)); end Write; BTW, why do not you use Ada.Streams? It is for things like this. --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-11 10:01 ` Q: " Dmitry A. Kazakov @ 2003-07-11 15:07 ` Michael Erdmann 2003-07-12 1:41 ` Jeffrey Carter 2003-07-14 8:48 ` Dmitry A. Kazakov 0 siblings, 2 replies; 35+ messages in thread From: Michael Erdmann @ 2003-07-11 15:07 UTC (permalink / raw) To: Dmitry A. Kazakov Dmitry A. Kazakov wrote: >>Does any body know, what this loop causes?! I am not sure >>if this is a bug or simply i missed the point. > > > Serialize is class-wide and a view conversion does not change the > tag..I.e. you have a re-dispatching case. Re-dispatching is a > dangerous thing. [I would like it removed from Ada] > > So Serialize re-dispatches to B.Write which again calls Serialize. > From design point of view, one should never call class-wide routines > from specific ones, this warranties that dispatch happens only once. > > I suppose that you want sort of procedure expansion instead of > complete overriding, if so, then you should explicitly call parent's > Write, similarly as one does it for Initialize/Finalize: > Unfortuantly this was not the complete code. The Serialize was itended to do a more complex job, which i have to replicate any where i want to serialize an object. The original serialize code looks some what like this: procedure Serialize( This : in Object'Class ) is ........ a := next(Attributes(This'Tag)) while a /= null loop Write( this.all, a.id ); a := next(....); end loop; end; The procedure write is a procedures which writes out a selected attribute of an object. The procedure Serialize the complete object. I would have been great when i could write something like this in ada: procedure Serialize( This : in Object'Class ) is Serialize( Super( This ) ); a := next(Attributes(This'Tag)) while a /= null loop Write( this.all, a.id ); a := next(....); end loop; end; I think something like this does not exist in Ada!? > package body B is > ... > procedure Write (This : in Object) is > begin > -- A.Serialize( A.Object( This ) ); > A.Write (A.Object (This)); -- Write parent's things > Put_Line( "Q =" & Natural'Image(This.Q)); > end Write; > > BTW, why do not you use Ada.Streams? It is for things like this. I fact i am using Ada.Stream, but as i have written above the code was simply a consended version. > > --- > Regards, > Dmitry Kazakov > www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-11 15:07 ` Michael Erdmann @ 2003-07-12 1:41 ` Jeffrey Carter 2003-07-14 8:48 ` Dmitry A. Kazakov 1 sibling, 0 replies; 35+ messages in thread From: Jeffrey Carter @ 2003-07-12 1:41 UTC (permalink / raw) Michael Erdmann wrote: > > a := next(Attributes(This'Tag)) > while a /= null loop > Write( this.all, a.id ); > a := next(....); > end loop; When you're in the habit of using "while" loops, you often write code like this. When you avoid them, you tend to write loop A := Next (Attributes (This'Tag) ); exit when a = null; Write (This.all, A.ID); end loop; which avoids the often dangerous code duplication required by using "while". -- Jeff Carter "I blow my nose on you." Monty Python & the Holy Grail ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-11 15:07 ` Michael Erdmann 2003-07-12 1:41 ` Jeffrey Carter @ 2003-07-14 8:48 ` Dmitry A. Kazakov 2003-07-14 18:38 ` Randy Brukardt 1 sibling, 1 reply; 35+ messages in thread From: Dmitry A. Kazakov @ 2003-07-14 8:48 UTC (permalink / raw) On Fri, 11 Jul 2003 17:07:52 +0200, Michael Erdmann <michael.erdmann@snafu.de> wrote: >Dmitry A. Kazakov wrote: > >>>Does any body know, what this loop causes?! I am not sure >>>if this is a bug or simply i missed the point. >> >> Serialize is class-wide and a view conversion does not change the >> tag..I.e. you have a re-dispatching case. Re-dispatching is a >> dangerous thing. [I would like it removed from Ada] >> >> So Serialize re-dispatches to B.Write which again calls Serialize. >> From design point of view, one should never call class-wide routines >> from specific ones, this warranties that dispatch happens only once. >> >> I suppose that you want sort of procedure expansion instead of >> complete overriding, if so, then you should explicitly call parent's >> Write, similarly as one does it for Initialize/Finalize: >> >Unfortuantly this was not the complete code. The Serialize was itended >to do a more complex job, which i have to replicate any where i want >to serialize an object. The original serialize code looks some what >like this: > >procedure Serialize( This : in Object'Class ) is > ........ > a := next(Attributes(This'Tag)) > while a /= null loop > Write( this.all, a.id ); > a := next(....); > end loop; > >end; > >The procedure write is a procedures which writes out a selected >attribute of an object. The procedure Serialize the complete >object. Thus from design point of view Write should never call Serialize. >I would have been great when i could write something >like this in ada: > >procedure Serialize( This : in Object'Class ) is > > Serialize( Super( This ) ); > > a := next(Attributes(This'Tag)) > while a /= null loop > Write( this.all, a.id ); > a := next(....); > end loop; > >end; It is a somewhat contradictory code. Serialize is either class-wide, or not. If it is then it should work for all Object'Class. Then it should not call itself. If it differs for different types then it has to be declared as a "normal" subroutine. I would split it in two: procedure Do_Serialize (This : Object'Class; As_If : Tag) is begin loop a := next (Attributes (As_If)); exit when a = null; Write (This, a.id); end loop; end Do_Serialize; procedure Serialize (This : in Some_Object) is begin Do_Serialize (This, Parent_Object'Tag); Do_Serialize (This, Some_Object'Tag); end Serialize; Though it is still a strange thing. Why parent's attributes cannot be extracted from an object using next? In other words, why do you want to extend Serialize? Why the following might be insufficient: procedure Serialize (This : Object'Class) is begin for Attribute in 1..Get_Number_Of_Attributes (This) loop Write (This, Attribute); end loop; end Serialize; >I think something like this does not exist in Ada!? Yes it does not. [Remote things] I wished Ada's OO be modified, 1. To have stricter contracts. Your case indicates an importance of contracts. When you write Object : constant Parent'Class := Create_Child; begin Foo (Parent (Object)); -- I am not what you think! you rightfully expect that the result be of Parent. But tagged types shamelessly break this. The result is not of Parent. It is still of Child because the conversion does not change the type tag. It is a clear contract violation, which leads to nasty surprises when later, in Foo, a re-dispatch happens. The source of the problem is that tag is a part of the object, so you cannot change it. OO-speaking the object has an identity which cannot be changed. It might be (and is) a great problem in other OOPL, but not in Ada which has T and T'Class different. So one might consistently state that T objects have no identity at all, while T'Class ones have it (through tag). And note, that nothing would be lost, because Rosen's trick would still allow you to add identity at your own risk. Alas, it wasn't made. If all types will become someday 'tagged', this should be changed. For present tagged types I would either forbid misleading view conversions to specific types or at least make them raising Constraint_Error if the source is not exactly of the target type: Parent (Object) -- Either illegal or Constraint_Error if not Parent Parent'Class (Object) -- Legal, and no surpises expected 2. To have an ability to refer the immediate parent [and visible ancestor] types. However, this feature should be carefully designed to keep a way free to multiple inheritance. Something like this: if X in S'Class then X'Super (S) is the most specific ancestor type in S'Class. For single inheritance case, it is abbreviated to S'Super. For tags 'Pred and 'Succ attributes should be defined to get tags along a derivation path: T'Pred (S) is the tag of a base type in S'Class, T'Succ (S) is the tag of a derived type in 'not S'Class or S' (all ancestors of S including S). Constraint_Error if the result does not exist or is ambiguous. --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-14 8:48 ` Dmitry A. Kazakov @ 2003-07-14 18:38 ` Randy Brukardt 2003-07-15 8:47 ` Dmitry A. Kazakov 0 siblings, 1 reply; 35+ messages in thread From: Randy Brukardt @ 2003-07-14 18:38 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:erm4hvsg533tp2hkhsj86tftu0s8i0ot9j@4ax.com... > 2. To have an ability to refer the immediate parent [and visible > ancestor] types. However, this feature should be carefully designed to > keep a way free to multiple inheritance. Something like this: > > if X in S'Class then X'Super (S) is the most specific ancestor type in > S'Class. For single inheritance case, it is abbreviated to S'Super. > > For tags 'Pred and 'Succ attributes should be defined to get tags > along a derivation path: > > T'Pred (S) is the tag of a base type in S'Class, T'Succ (S) is the tag > of a derived type in 'not S'Class or S' (all ancestors of S including > S). Constraint_Error if the result does not exist or is ambiguous. We discussed something like this when we were discussing controlling dispatching. However, there is a significant problem in that a type can have two (related) parents: package P is type NT is new T1 with private; private type NT is new T2 with private; end P; with P; procedure Q is begin NT'Parent -- ??? Does NT'Parent refer to T1 or T2? If it returns T2, we're breaking privateness (with all of the methodlogical and implementation problems that entails). If it returns T1, we're not really getting the right answer, and moreover, the result changes with visibility (yuck!). Thus, we haven't really moved forward on this. Randy. ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-14 18:38 ` Randy Brukardt @ 2003-07-15 8:47 ` Dmitry A. Kazakov 2003-07-15 17:23 ` Randy Brukardt 0 siblings, 1 reply; 35+ messages in thread From: Dmitry A. Kazakov @ 2003-07-15 8:47 UTC (permalink / raw) On Mon, 14 Jul 2003 13:38:14 -0500, "Randy Brukardt" <randy@rrsoftware.com> wrote: >"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >news:erm4hvsg533tp2hkhsj86tftu0s8i0ot9j@4ax.com... >> 2. To have an ability to refer the immediate parent [and visible >> ancestor] types. However, this feature should be carefully designed to >> keep a way free to multiple inheritance. Something like this: >> >> if X in S'Class then X'Super (S) is the most specific ancestor type in >> S'Class. For single inheritance case, it is abbreviated to S'Super. >> >> For tags 'Pred and 'Succ attributes should be defined to get tags >> along a derivation path: >> >> T'Pred (S) is the tag of a base type in S'Class, T'Succ (S) is the tag >> of a derived type in 'not S'Class or S' (all ancestors of S including >> S). Constraint_Error if the result does not exist or is ambiguous. > >We discussed something like this when we were discussing controlling >dispatching. However, there is a significant problem in that a type can have >two (related) parents: > > package P is > type NT is new T1 with private; > private > type NT is new T2 with private; > end P; > > with P; > procedure Q is > begin > NT'Parent -- ??? > >Does NT'Parent refer to T1 or T2? If it returns T2, we're breaking >privateness (with all of the methodlogical and implementation problems that >entails). If it returns T1, we're not really getting the right answer, and >moreover, the result changes with visibility (yuck!). > >Thus, we haven't really moved forward on this. Ah, you mean this: package A is type X is tagged null record; type XX is new X with null record; end A; with A; use A; package B is type Y is new X with private; private type Y is new XX with null record; end B; It is an interesting case. Though I see little harm if Y'Parent would give different answers depending on scope. It would be indeed nasty if somebody would try to call Y'Parent.Finalize, but why should one wish a thing like that? Anyway if he would using explicit type specification, then he could get nothing better than Y'Parent would offer. But I agree that it is unattractive. Probably it is worth to think how to eliminate any need in Y'Parent? For example one could provide some sort of overriding by extension. I.e. the bodies which would implicitly call the overriden body, as it is manually made in Initialize/Finalize. --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-15 8:47 ` Dmitry A. Kazakov @ 2003-07-15 17:23 ` Randy Brukardt 2003-07-16 8:08 ` Dmitry A. Kazakov 0 siblings, 1 reply; 35+ messages in thread From: Randy Brukardt @ 2003-07-15 17:23 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:h5c7hvgol0sscrnaj98qp071903m9hoh5c@4ax.com... > Probably it is worth to think how to eliminate any need in Y'Parent? > For example one could provide some sort of overriding by extension. > I.e. the bodies which would implicitly call the overriden body, as it > is manually made in Initialize/Finalize. Interesting idea, but you'd need some way to specify when the overridden body is called. For instance, you usually call the overridden body first for Initialize (so the parent components are Initialized before you do anything) and last for Finalize (so the parent components still exist while you are writing your code). I've even had a few cases where I had to do it in the middle (with operations before an after it). Randy. ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-15 17:23 ` Randy Brukardt @ 2003-07-16 8:08 ` Dmitry A. Kazakov 2003-07-16 17:44 ` Robert I. Eachus 2003-07-17 1:57 ` Robert A Duff 0 siblings, 2 replies; 35+ messages in thread From: Dmitry A. Kazakov @ 2003-07-16 8:08 UTC (permalink / raw) On Tue, 15 Jul 2003 12:23:29 -0500, "Randy Brukardt" <randy@rrsoftware.com> wrote: >"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >news:h5c7hvgol0sscrnaj98qp071903m9hoh5c@4ax.com... >> Probably it is worth to think how to eliminate any need in Y'Parent? >> For example one could provide some sort of overriding by extension. >> I.e. the bodies which would implicitly call the overriden body, as it >> is manually made in Initialize/Finalize. > >Interesting idea, but you'd need some way to specify when the overridden >body is called. For instance, you usually call the overridden body first for >Initialize (so the parent components are Initialized before you do anything) >and last for Finalize (so the parent components still exist while you are >writing your code). I've even had a few cases where I had to do it in the >middle (with operations before an after it). One should invent a good syntax suggar for this. Which is rather difficult. There are actually two things in it: 1. There should be a way to declare some primitive operation saying that it cannot be overriden completely. One might wish it for things like Initialize/Finalize. Then probably there should be a way to say where an override is allowed to add something. 2. During overriding one should specifiy where the override(s) places the extension. I think that it should be specified in the body, while the specification should only say that it gets overridden. The question is syntax and a good balance between 1. and 2., i.e between contract and implementation. The most complicated cases would emerge from things like Adjust, I suppose. It is also related to an ability to explicitly specify that a subroutine is an overriding, not overloading, to avoid undesired overloading in case ot typo errors. I do not know whether there is an AI on that. If yes, they should be considered together. --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-16 8:08 ` Dmitry A. Kazakov @ 2003-07-16 17:44 ` Robert I. Eachus 2003-07-17 1:57 ` Robert A Duff 1 sibling, 0 replies; 35+ messages in thread From: Robert I. Eachus @ 2003-07-16 17:44 UTC (permalink / raw) Dmitry A. Kazakov wrote: > One should invent a good syntax suggar for this. Which is rather > difficult. There are actually two things in it: That is putting it VERY mildly. > 1. There should be a way to declare some primitive operation saying > that it cannot be overriden completely. One might wish it for things > like Initialize/Finalize. Then probably there should be a way to say > where an override is allowed to add something. > > 2. During overriding one should specifiy where the override(s) places > the extension. I think that it should be specified in the body, while > the specification should only say that it gets overridden. > > The question is syntax and a good balance between 1. and 2., i.e > between contract and implementation. The most complicated cases would > emerge from things like Adjust, I suppose. > It is also related to an ability to explicitly specify that a > subroutine is an overriding, not overloading, to avoid undesired > overloading in case ot typo errors. I do not know whether there is an > AI on that. If yes, they should be considered together. There is an AI on this (AI-218). If you try to follow the discussion, you eyes will quickly glaze over. It needs to be fixed, it probably will be fixed, but there is a slight problem. There can be multiple views of a subprogram declaration, and in some views it will be overriding, while in others it is not. This is both why a "confirming" keyword is currently the leading candidate for Ada0Y, and why it is so hard. We don't want a solution that requires a programmer to explicitly confirm the wrong view: package P is type T is tagged private; private type T is new Ada.Finalization.Controlled with...; end P; package P.Q is type NT is new T; procedure Initialize(X: in out NT); -- overriding? Not here. private -- but it is here. procedure Finalize(X: in out NT); -- overriding? Yes, and here. end P.Q; I favor the pragma solution, because you can put the pragma at the point where it says "but it is here," and not confuse anyone. Most ARG members seem to prefer the keyword solution, which requires an "extra" declaration at that point just to use the keyword. Note that 90% of the potential uses are simple. The other 10% are cases where the compiler will probably end up providing education to Ada programmers. Getting that education as painless as possible is the real problem. -- Robert I. Eachus �In an ally, considerations of house, clan, planet, race are insignificant beside two prime questions, which are: 1. Can he shoot? 2. Will he aim at your enemy?� -- from the Laiden novels by Sharon Lee and Steve Miller. ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-16 8:08 ` Dmitry A. Kazakov 2003-07-16 17:44 ` Robert I. Eachus @ 2003-07-17 1:57 ` Robert A Duff 2003-07-18 9:10 ` Dale Stanbrough 1 sibling, 1 reply; 35+ messages in thread From: Robert A Duff @ 2003-07-17 1:57 UTC (permalink / raw) Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes: > One should invent a good syntax suggar for this. Which is rather > difficult. There are actually two things in it: > > 1. There should be a way to declare some primitive operation saying > that it cannot be overriden completely. One might wish it for things > like Initialize/Finalize. Then probably there should be a way to say > where an override is allowed to add something. > > 2. During overriding one should specifiy where the override(s) places > the extension. I think that it should be specified in the body, while > the specification should only say that it gets overridden. Common Lisp (CLOS) has some stuff like this. > The question is syntax and a good balance between 1. and 2., i.e > between contract and implementation. The most complicated cases would > emerge from things like Adjust, I suppose. > > It is also related to an ability to explicitly specify that a > subroutine is an overriding, not overloading, to avoid undesired > overloading in case ot typo errors. I do not know whether there is an > AI on that. If yes, they should be considered together. Yes, there is such an AI. - Bob ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-17 1:57 ` Robert A Duff @ 2003-07-18 9:10 ` Dale Stanbrough 2003-07-18 20:26 ` Robert I. Eachus 0 siblings, 1 reply; 35+ messages in thread From: Dale Stanbrough @ 2003-07-18 9:10 UTC (permalink / raw) Robert A Duff <bobduff@shell01.TheWorld.com> wrote: > > It is also related to an ability to explicitly specify that a > > subroutine is an overriding, not overloading, to avoid undesired > > overloading in case ot typo errors. I do not know whether there is an > > AI on that. If yes, they should be considered together. > > Yes, there is such an AI. Does it cover the opposite where due to a typo you haven't overridden a subprogram? Dale ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-18 9:10 ` Dale Stanbrough @ 2003-07-18 20:26 ` Robert I. Eachus 2003-07-18 21:35 ` tmoran 2003-07-19 14:44 ` Chad R. Meiners 0 siblings, 2 replies; 35+ messages in thread From: Robert I. Eachus @ 2003-07-18 20:26 UTC (permalink / raw) Dale Stanbrough wrote: > Does it cover the opposite where due to a typo you haven't overridden a > subprogram? That is the major impetus behind it. If you think you are overriding, and the compiler doesn't, there is an error. It can be in your understanding of the situation, the compiler's understanding, or just be a typo. The problem is, as I said is WHERE the declaration is overriding. I created an example: -------------------------------------------------------------------------- Now my head really hurts! Are you saying that the original derived Finalize declaration really can't be overridden and that in this case (or in this case with Finalize spelled right) dispatching still calls the implicit operation? I hope not, and that this is just semantics. Let me create a better example (in current Ada): with Ada.Finalization; package Root is type Root_Type is tagged private; function Value (Object : Root_Type) return Integer; procedure Set (Object : in out Root_Type; Value: in Integer); private type Root_Type is new Ada.Finalization.Controlled with record Init_Case: Integer := 3; end record; procedure Initialize (Object : in out Root_Type); -- 1 -- Finalization hidden in private part to since Controlled is -- hidden. end Root; package body Root is function Value (Object : Root_Type) return Integer is begin return Object.Init_Case; end Value; procedure Set (Object : in out Root_Type; Value: in Integer) is begin Object.Init_Case := Value; end Set; procedure Initialize (Object : in out Root_Type) is begin Object.Init_Case := 1; end Initialize; end Root; with Root; package Leaf is type Derived_Type is new Root.Root_Type with null record; -- derived type is known to be tagged but not controlled. procedure Initialize (Object : in out Derived_Type); -- 2 -- Tucker says this is not overriding, right? end Leaf; package body Leaf is procedure Initialize (Object : in out Derived_Type) is begin Set(Object, 2); end Initialize; end Leaf; with Leaf; with Ada.Text_IO; use Ada.Text_IO; procedure Sample is Obj : Leaf.Derived_Type; -- Which Initialize gets called? begin case Leaf.Value(Obj) is when 1 => Put_Line(" Root.Initialize Called."); when 2 => Put_Line(" Leaf.Initialize Called."); when 3 => Put_Line(" No initialization!"); when others => Put_Line(" I give up!"); end case; end Sample; E:\Ada\Test\AI-218>sample Leaf.Initialize Called. At least GNAT agrees with me. ;-) Seriously I think that Tucker may be correct, "by the book." But to not be able to declare Leaf.Initialize as overriding defeats the whole point. Sigh. So now even if we adopt my solution or the new syntax, we still have to change 7.3.1 to get the definition of overriding to agree with the (to me) commonsense definition. ------------------------------------------------------------------------ As you will see if you read the whole discussion, other compilers do NOT agree with me. For some reason Tucker's compiler agrees with him. ;-) And of course, I haven't submitted this as a bug against GNAT until the AI as a whole is resolved. Incidently I am posting this here to give the spectators a view of what is going on. This is a hard and non-trivial issue. It might be nice if in the final version, declaring Leaf.Initialize to be overriding could "pierce the privateness" and cause it to be so. I went out of my way in writing this code, so that there is no location where Leaf.Initialize is overriding. (At least as Tucker and the RM seem to currently define overriding.) But as I say, the (very hard) issue is to come up with a way to do add the overriding keyword so that it helps users overall. The "little test" of putting the overriding declaration in the right place is a potential huge pain to users. (If Leaf was a child of Root, then Initialize would be overriding in the body and in the private part of Leaf if there was one. Obviously in that case declaring Leaf.Initialize as non-overriding helps no one.) -- Robert I. Eachus �In an ally, considerations of house, clan, planet, race are insignificant beside two prime questions, which are: 1. Can he shoot? 2. Will he aim at your enemy?� -- from the Laiden novels by Sharon Lee and Steve Miller. ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-18 20:26 ` Robert I. Eachus @ 2003-07-18 21:35 ` tmoran 2003-07-19 0:25 ` Robert I. Eachus 2003-07-19 14:44 ` Chad R. Meiners 1 sibling, 1 reply; 35+ messages in thread From: tmoran @ 2003-07-18 21:35 UTC (permalink / raw) What was programmer of Root trying to accomplish when he said > type Root_Type is tagged private; It seems to me he was trying to say "If you declare a child type and procedures Initialize or Finalize or Adjust, don't expect them to be called as if Root_Type was Controlled. If he wanted to let derived types be Controlled, he should have said: > type Root_Type is new Ada.Finalization.Controlled with private; > But to not be able to declare Leaf.Initialize > as overriding defeats the whole point. Defeats what point? ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-18 21:35 ` tmoran @ 2003-07-19 0:25 ` Robert I. Eachus 2003-07-19 2:30 ` tmoran 0 siblings, 1 reply; 35+ messages in thread From: Robert I. Eachus @ 2003-07-19 0:25 UTC (permalink / raw) tmoran@acm.org wrote: > What was programmer of Root trying to accomplish when he said > >> type Root_Type is tagged private; He was trying to demonstrate an obscure point about the current definition of overriding. I typically say that, for most Ada programmers 10% of the Reference Manual is relevant, the rest explains in gruesome detail what will happen if you try to shoot yourself in the foot. The ARG combs through that ninety percent, finds the one percent where it is not clear which foot you should hit and worries about it for years. Example programs like this, and like most of the ACATS tests are about consistently hitting the same toe when you miss what you are aiming at. Only a small very fun part of the job is adding new features to the language. (But for every new useful feature, there are also at least ten new ways to shoot at your feet. So the big part of the job is corralling all those nasal daemons. > It seems to me he was trying to say "If you declare a child type > and procedures Initialize or Finalize or Adjust, don't expect them > to be called as if Root_Type was Controlled. If he wanted to let > derived types be Controlled, he should have said: > >> type Root_Type is new Ada.Finalization.Controlled with private; Could have, should have, will learn to. All irrelevant, as I said, the discussion on this starts with the assumptions of gun and foot. The ARG wants to make the foot smaller and the gun harder to point at your own body. But we are only human, the solutions are imperfect, and somewhere out there is a bigger fool than I can imagine. I have to content myself with saving those I can hope to understand. There is another thread about let me find it: --------- test.ads --------- with System.Storage_Elements; use System.Storage_Elements; package Test is type A is record I: Integer; end record; B: A; J: Integer renames B.I; for J'Address use To_Address(0); end Test; --------------------------- What was the author of this code TRYING to do? I have yet to answer that one. If there is a real need here, I should try to find some answer other than, "You may be entitled to a better error message." Does RM 13.3(12) explicitly disallow this case? Yes. Address may be specified for stand-alone objects and for program units via an attribute_definition_clause. Stand-alone object is a technical term defined in RM 3.3.1(1): "An object_declaration declares a stand-alone object with a given nominal subtype..." Since J is declared by a renaming declaration, it is not a stand-alone object. And per 13.3(5), the RM decides where a non-implementation defined attribute can appear in an attribute definition clause. >>But to not be able to declare Leaf.Initialize >>as overriding defeats the whole point. > > Defeats what point? In this case the idea of extending the language to allow the programmer to state whether he expects the declaration to be overriding. Making something overriding and only allowing a user to declare it as non-overriding clearly defeats that intent. So most of the discussion is about how to allow these declarations to be true. No, I'm not crazy and it is hard. Remember any changes that affect real software out in the world require a huge benefit. So we want to fix this without breaking what exists. Note that for this particular example I wrote, whatever is decided will break it. But that is fine. It was written only for exploratory reasons, and whatever the final resolution is, ALL compilers will produce the same output. -- Robert I. Eachus �In an ally, considerations of house, clan, planet, race are insignificant beside two prime questions, which are: 1. Can he shoot? 2. Will he aim at your enemy?� -- from the Laiden novels by Sharon Lee and Steve Miller. ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-19 0:25 ` Robert I. Eachus @ 2003-07-19 2:30 ` tmoran 2003-07-19 5:48 ` Robert I. Eachus 0 siblings, 1 reply; 35+ messages in thread From: tmoran @ 2003-07-19 2:30 UTC (permalink / raw) > > What was programmer of Root trying to accomplish when he said > > > >> type Root_Type is tagged private; > > He was trying to demonstrate an obscure point ;) But to rephrase the question: Why would an application programmer write type Root_Type is tagged private; instead of type Root_Type is new Ada.Finalization.Controlled with private; unless he specifically did not want derived types to do their own Initialize et al. As I understand: > -- derived type is known to be tagged but not controlled. > procedure Initialize (Object : in out Derived_Type); -- 2 > ... > Obj : Leaf.Derived_Type; -- Which Initialize gets called? > Leaf.Initialize Called. > > At least GNAT agrees with me. ;-) you and Gnat believe that type Root_Type is tagged private; type Root_Type is new Ada.Finalization.Controlled with private; should be equivalent, right? It seems to me that additional ways to say the same thing are of modest value, while ways to say something different are of greater value, so I would want those two declarations to accomplish different, not the same, things. ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-19 2:30 ` tmoran @ 2003-07-19 5:48 ` Robert I. Eachus 2003-07-21 8:38 ` Dmitry A. Kazakov 0 siblings, 1 reply; 35+ messages in thread From: Robert I. Eachus @ 2003-07-19 5:48 UTC (permalink / raw) tmoran@acm.org wrote: > type Root_Type is tagged private; > type Root_Type is new Ada.Finalization.Controlled with private; > should be equivalent, right? It seems to me that additional ways to > say the same thing are of modest value, while ways to say something > different are of greater value, so I would want those two declarations > to accomplish different, not the same, things. No I believe that having TWO dispatching operations named Initialize, and which one is called depends on whether the call is implicit or explicit is potentially confusing to users. The same effect occurs if you have two objects with default initializations, and the one in the package spec calls one version of Initialize, and the one in the package calls a different Initialize. This as I said was a small program to demonstrate where the people on both sides of the discussion weren't "getting it." I wanted to demonstrate that even if everyone did have the identical understanding of the overridding rules, these funny cases do exist. (Remember the part about users shooting themselves in the foot.) And in the worst cases, the point at which the overriding occurs does affect run-time behavior. The fact that I tripped over a case where compilers disagree tells us (the ARG) two things: 1) There is definitely a problem. 2) If it was a serious problem, users would have already run into it. I can't testify that users hadn't tripped over it before, but now it is definitely out in the open. Which rule do you prefer: 1) All objects of a type derived from Ada.Finalization.Controlled by default call the same version of Initialize? or 2) Information hiding in effect AT THE PLACE OF THE CALL can determine which version of a subprogram is called? If you vote for 2), I won't argue, I'll take it as data. The important part for the ARG is that in this (foot shooting) case we have to choose. The two alternatives are clearly incompatible, and that is what the program was written to demostrate. -- Robert I. Eachus �In an ally, considerations of house, clan, planet, race are insignificant beside two prime questions, which are: 1. Can he shoot? 2. Will he aim at your enemy?� -- from the Laiden novels by Sharon Lee and Steve Miller. ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-19 5:48 ` Robert I. Eachus @ 2003-07-21 8:38 ` Dmitry A. Kazakov 2003-07-21 10:08 ` Robert I. Eachus 0 siblings, 1 reply; 35+ messages in thread From: Dmitry A. Kazakov @ 2003-07-21 8:38 UTC (permalink / raw) On Sat, 19 Jul 2003 05:48:23 GMT, "Robert I. Eachus" <rieachus@attbi.com> wrote: >1) All objects of a type derived from Ada.Finalization.Controlled by >default call the same version of Initialize? Which one version? How a public part might know that there is a privately declared Initialize? >or > >2) Information hiding in effect AT THE PLACE OF THE CALL can determine >which version of a subprogram is called? For good or bad, but this was the intention, i.e. to hide Initialize and here you are. >If you vote for 2), I won't argue, I'll take it as data. The important >part for the ARG is that in this (foot shooting) case we have to choose. > The two alternatives are clearly incompatible, and that is what the >program was written to demostrate. IMO the problem is that you can have both an overloading in the public part and an overriding in the private. This is a nasty problem, because: 1<-->A. if we prohibit this, we would expose something from the private part; 2<-->B. if we accept this, we have pitfalls as your example shows. I think that the syntax should clearly distinguish declaring a primitive (and thus overriding) vs. non-primitive (overloading) subprogram. Further, no matter how painful it could be, one should probably outlaw non-primitive subprograms with tagged non-class-wide arguments. This again would solve little as long as a type can be publicly non-tagged, being tagged privately. So again I have to repeat the same old slogan: ALL TYPES BE TAGGED! --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-21 8:38 ` Dmitry A. Kazakov @ 2003-07-21 10:08 ` Robert I. Eachus 2003-07-21 13:21 ` Dmitry A. Kazakov 0 siblings, 1 reply; 35+ messages in thread From: Robert I. Eachus @ 2003-07-21 10:08 UTC (permalink / raw) Dmitry A. Kazakov wrote: >>1) All objects of a type derived from Ada.Finalization.Controlled by >>default call the same version of Initialize? > > Which one version? How a public part might know that there is a > privately declared Initialize? > >>or >> >>2) Information hiding in effect AT THE PLACE OF THE CALL can determine >>which version of a subprogram is called? > > For good or bad, but this was the intention, i.e. to hide Initialize > and here you are. Yep. > I think that the syntax should clearly distinguish declaring a > primitive (and thus overriding) vs. non-primitive (overloading) > subprogram. Further, no matter how painful it could be, one should > probably outlaw non-primitive subprograms with tagged non-class-wide > arguments. Actually the syntax is such that it is very difficult to have tagged types which are not publically tagged. (I used to drive Tuck crazy, I think, during the Ada 9X process with examples using generic instantiations to get a type declared as "type Visible is private;" but which was actually a tagged type. But let's leave those cases aside for a moment. The real devilish problem occurs when the public type is tagged: type Public is tagged private; procedure Initialize(X: in out Public); and the full declaration: type Public is new Ada.Finalization.Controlled with... results in a subprogram becoming overriding in part of its scope. That is what pushes for choice 1 above. It is clear that currently 2 is intended by the RM, but if anyone finds themselves in this mess the likelihood that they will "get it right" is low. (Remember, not even GNAT does.) Also note that, in the above example, declaring Initialize (publicly) non-overriding is actively harmful. I've suggested a "will override" choice for the pragma or keyword. But as you say, that exposes what the programmer obviously knows is going to happen in the private part. Note that there are cases where you have a child package containing a type derived from a private type in the parent package, and where you NEED for the "will override" operation to be public. It is not an easy problem. -- Robert I. Eachus �In an ally, considerations of house, clan, planet, race are insignificant beside two prime questions, which are: 1. Can he shoot? 2. Will he aim at your enemy?� -- from the Laiden novels by Sharon Lee and Steve Miller. ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-21 10:08 ` Robert I. Eachus @ 2003-07-21 13:21 ` Dmitry A. Kazakov 2003-07-21 18:51 ` Robert I. Eachus 0 siblings, 1 reply; 35+ messages in thread From: Dmitry A. Kazakov @ 2003-07-21 13:21 UTC (permalink / raw) On Mon, 21 Jul 2003 10:08:45 GMT, "Robert I. Eachus" <rieachus@attbi.com> wrote: >Dmitry A. Kazakov wrote: > >>>1) All objects of a type derived from Ada.Finalization.Controlled by >>>default call the same version of Initialize? >> >> Which one version? How a public part might know that there is a >> privately declared Initialize? >> >>>or >>> >>>2) Information hiding in effect AT THE PLACE OF THE CALL can determine >>>which version of a subprogram is called? >> >> For good or bad, but this was the intention, i.e. to hide Initialize >> and here you are. > >Yep. > >> I think that the syntax should clearly distinguish declaring a >> primitive (and thus overriding) vs. non-primitive (overloading) >> subprogram. Further, no matter how painful it could be, one should >> probably outlaw non-primitive subprograms with tagged non-class-wide >> arguments. > >Actually the syntax is such that it is very difficult to have tagged >types which are not publically tagged. (I used to drive Tuck crazy, I >think, during the Ada 9X process with examples using generic >instantiations to get a type declared as "type Visible is private;" but >which was actually a tagged type. But let's leave those cases aside for >a moment. The real devilish problem occurs when the public type is tagged: > > type Public is tagged private; > > procedure Initialize(X: in out Public); > >and the full declaration: > > type Public is new Ada.Finalization.Controlled with... > >results in a subprogram becoming overriding in part of its scope. That >is what pushes for choice 1 above. It is clear that currently 2 is >intended by the RM, but if anyone finds themselves in this mess the >likelihood that they will "get it right" is low. (Remember, not even >GNAT does.) Also note that, in the above example, declaring Initialize >(publicly) non-overriding is actively harmful. Ah, and people are still claiming that multiple inheritance is a bad thing! Now look at this "single" inheritance. Actually, it is multiple! You declare, publicly, that X has Initialize, this is the interface No.1. Then in the private part you derive from Ada.Finalization.Controlled, but this is the interface No.2. Now you want to reconcile both having only single [interface] inheritance? It is a clear contradiction. Should we have solved MI, the above were for free. Another evil is that constructors/destructors are exposed as "normal" operations having some special semantincs attached to them *depending* on the context. This also won't work. The word "Initialize" suddenly becomes some very special for the compiler in the private part, being just a name in the public one. If it were just a procedure Foo, one could probably live with it. >I've suggested a "will override" choice for the pragma or keyword. But >as you say, that exposes what the programmer obviously knows is going to >happen in the private part. IMO it should be illegal with any pragma: package A is type Public is tagged private; procedure Initialize(X: in out Public); private type Public is new Ada.Finalization.Controlled with... -- Error public and private views are incompatible! end A; It could be made legal only if primitive operation disallowing were supported: package A is type Public is tagged private; procedure Initialize(X: in out Public); private type Public is new Ada.Finalization.Controlled with... procedure Ada.Finalization.Controlled.Initialize (X: in out Public) is null; -- Down with it! -- Fine, now both views are compatible end A; A more interesting case: package AA is type Public is tagged private; private type Public is new Ada.Finalization.Controlled with... end AA; with AA; use AA; package B is type Public_Public is new Public with private; procedure Initialize(X: in out Public_Public); -- This is legal. B knows nothing about Public's origin -- so it cannot misuse it private type Public_Public is new Public with ... end B package AA.C is type Private_Public is new Public with private; procedure Initialize(X: in out Public_Public); -- This is an error. C knows Public's private, so -- its private part is illegal private type Private_Public is new Public with ... end AA.C > Note that there are cases where you have a >child package containing a type derived from a private type in the >parent package, and where you NEED for the "will override" operation to >be public. It is not an easy problem. --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-21 13:21 ` Dmitry A. Kazakov @ 2003-07-21 18:51 ` Robert I. Eachus 2003-07-22 7:41 ` Dmitry A. Kazakov 0 siblings, 1 reply; 35+ messages in thread From: Robert I. Eachus @ 2003-07-21 18:51 UTC (permalink / raw) Dmitry A. Kazakov wrote: > Another evil is that constructors/destructors are exposed as "normal" > operations having some special semantincs attached to them *depending* > on the context. This also won't work. The word "Initialize" suddenly > becomes some very special for the compiler in the private part, being > just a name in the public one. If it were just a procedure Foo, one > could probably live with it. Initialize (and for that matter Ada.Finalization) is just a convenient scapegoat to use in examples. The problems can occur with any predefined operations of a tagged type. (But there is this one package in the RM that declares tagged types which is why it tends to get used in examples.) > IMO it should be illegal with any pragma: > > package A is > type Public is tagged private; > procedure Initialize(X: in out Public); > private > type Public is new Ada.Finalization.Controlled with... > -- Error public and private views are incompatible! > end A; > > It could be made legal only if primitive operation disallowing were > supported: That is an interesting approach. I can't see justifying disallowing it entirely, but saying that: not overriding procedure Initialize(X: in out Public); -- or whatever syntax is chosen becomes illegal in the private part might be a good idea. At least it prevents the misleading use of the keywords. If we still have "may override" and add my "will override" then the programmer gets to choose what to say publicly, which is nice, and still get the advantage of the compiler checking his assertions. > A more interesting case: > > package AA is > type Public is tagged private; > private > type Public is new Ada.Finalization.Controlled with... > end AA; > > with AA; use AA; > package B is > type Public_Public is new Public with private; > procedure Initialize(X: in out Public_Public); > -- This is legal. B knows nothing about Public's origin > -- so it cannot misuse it > private > type Public_Public is new Public with ... > end B > > package AA.C is > type Private_Public is new Public with private; > procedure Initialize(X: in out Public_Public); > -- This is an error. C knows Public's private, so > -- its private part is illegal > private > type Private_Public is new Public with ... > end AA.C Change Private_Public to new Public_Public with private and you will begin to understand the problem. AA.C.Initialize would override B.Initialize everywhere, but would only override AA.Initalize, assuming that there is one, in some areas of its scope. -- Robert I. Eachus �In an ally, considerations of house, clan, planet, race are insignificant beside two prime questions, which are: 1. Can he shoot? 2. Will he aim at your enemy?� -- from the Laiden novels by Sharon Lee and Steve Miller. ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-21 18:51 ` Robert I. Eachus @ 2003-07-22 7:41 ` Dmitry A. Kazakov 2003-07-22 10:36 ` Lutz Donnerhacke 0 siblings, 1 reply; 35+ messages in thread From: Dmitry A. Kazakov @ 2003-07-22 7:41 UTC (permalink / raw) On Mon, 21 Jul 2003 18:51:34 GMT, "Robert I. Eachus" <rieachus@attbi.com> wrote: >Dmitry A. Kazakov wrote: > >> Another evil is that constructors/destructors are exposed as "normal" >> operations having some special semantincs attached to them *depending* >> on the context. This also won't work. The word "Initialize" suddenly >> becomes some very special for the compiler in the private part, being >> just a name in the public one. If it were just a procedure Foo, one >> could probably live with it. > >Initialize (and for that matter Ada.Finalization) is just a convenient >scapegoat to use in examples. The problems can occur with any >predefined operations of a tagged type. Yes, but for Initialize/Finalize the consequences are usually catastrophic. This is why I would prefer either a special syntax (C++ way), or a more general approach with overriding by extension. Which can be later well re-used: 1. for user-defined aggregates, if they come; 2. for overriding entry points of tagged tasks, if ...; 3. for overriding operations of tagged protected objects, if ...; >(But there is this one package >in the RM that declares tagged types which is why it tends to get used >in examples.) > >> IMO it should be illegal with any pragma: >> >> package A is >> type Public is tagged private; >> procedure Initialize(X: in out Public); >> private >> type Public is new Ada.Finalization.Controlled with... >> -- Error public and private views are incompatible! >> end A; >> >> It could be made legal only if primitive operation disallowing were >> supported: > >That is an interesting approach. I can't see justifying disallowing it >entirely, but saying that: > > not overriding procedure Initialize(X: in out Public); > -- or whatever syntax is chosen > >becomes illegal in the private part might be a good idea. At least it >prevents the misleading use of the keywords. If we still have "may >override" and add my "will override" then the programmer gets to choose >what to say publicly, which is nice, and still get the advantage of the >compiler checking his assertions. > >> A more interesting case: >> >> package AA is >> type Public is tagged private; >> private >> type Public is new Ada.Finalization.Controlled with... >> end AA; >> >> with AA; use AA; >> package B is >> type Public_Public is new Public with private; >> procedure Initialize(X: in out Public_Public); >> -- This is legal. B knows nothing about Public's origin >> -- so it cannot misuse it >> private >> type Public_Public is new Public with ... >> end B >> >> package AA.C is >> type Private_Public is new Public with private; >> procedure Initialize(X: in out Public_Public); >> -- This is an error. C knows Public's private, so >> -- its private part is illegal >> private >> type Private_Public is new Public with ... >> end AA.C > >Change Private_Public to new Public_Public with private and you will >begin to understand the problem. AA.C.Initialize would override >B.Initialize everywhere, but would only override AA.Initalize, assuming >that there is one, in some areas of its scope. If you mean this: with B; use B; package AA.D is type Private_Public_Public is new Public_Public with ...; end AA.D; then it should be again a compile error, because AA.C "knows" that Public_Public has a private Initialize which collides with the public one. The rule is simple - there should be no way to create a context where both versions of Initialize could be visible. --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-22 7:41 ` Dmitry A. Kazakov @ 2003-07-22 10:36 ` Lutz Donnerhacke 2003-07-22 12:11 ` Dmitry A. Kazakov 0 siblings, 1 reply; 35+ messages in thread From: Lutz Donnerhacke @ 2003-07-22 10:36 UTC (permalink / raw) * Dmitry A Kazakov wrote: > On Mon, 21 Jul 2003 18:51:34 GMT, "Robert I. Eachus" >>Initialize (and for that matter Ada.Finalization) is just a convenient >>scapegoat to use in examples. The problems can occur with any >>predefined operations of a tagged type. > > Yes, but for Initialize/Finalize the consequences are usually > catastrophic. This is why I would prefer either a special syntax (C++ > way), or a more general approach with overriding by extension. Which > can be later well re-used: > > 1. for user-defined aggregates, if they come; > 2. for overriding entry points of tagged tasks, if ...; > 3. for overriding operations of tagged protected objects, if ...; How about a fixing rule, which applies at the private syntax element? ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-22 10:36 ` Lutz Donnerhacke @ 2003-07-22 12:11 ` Dmitry A. Kazakov 2003-07-22 12:18 ` Lutz Donnerhacke 0 siblings, 1 reply; 35+ messages in thread From: Dmitry A. Kazakov @ 2003-07-22 12:11 UTC (permalink / raw) On Tue, 22 Jul 2003 10:36:56 +0000 (UTC), Lutz Donnerhacke <lutz@iks-jena.de> wrote: >* Dmitry A Kazakov wrote: >> On Mon, 21 Jul 2003 18:51:34 GMT, "Robert I. Eachus" >>>Initialize (and for that matter Ada.Finalization) is just a convenient >>>scapegoat to use in examples. The problems can occur with any >>>predefined operations of a tagged type. >> >> Yes, but for Initialize/Finalize the consequences are usually >> catastrophic. This is why I would prefer either a special syntax (C++ >> way), or a more general approach with overriding by extension. Which >> can be later well re-used: >> >> 1. for user-defined aggregates, if they come; >> 2. for overriding entry points of tagged tasks, if ...; >> 3. for overriding operations of tagged protected objects, if ...; > >How about a fixing rule, which applies at the private syntax element? Which rule do you mean? --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-22 12:11 ` Dmitry A. Kazakov @ 2003-07-22 12:18 ` Lutz Donnerhacke 2003-07-22 14:46 ` Dmitry A. Kazakov 0 siblings, 1 reply; 35+ messages in thread From: Lutz Donnerhacke @ 2003-07-22 12:18 UTC (permalink / raw) * Dmitry A Kazakov wrote: > On Tue, 22 Jul 2003 10:36:56 +0000 (UTC), Lutz Donnerhacke >>How about a fixing rule, which applies at the private syntax element? > > Which rule do you mean? If publicly defined tagged types are fixed at the private syntax element, there is no possibility to define dispatching procedures and functions afterwards. Of course, it's not a choice, because it will break existing programs. ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-22 12:18 ` Lutz Donnerhacke @ 2003-07-22 14:46 ` Dmitry A. Kazakov 2003-07-22 15:11 ` Lutz Donnerhacke 0 siblings, 1 reply; 35+ messages in thread From: Dmitry A. Kazakov @ 2003-07-22 14:46 UTC (permalink / raw) On Tue, 22 Jul 2003 12:18:57 +0000 (UTC), Lutz Donnerhacke <lutz@iks-jena.de> wrote: >* Dmitry A Kazakov wrote: >> On Tue, 22 Jul 2003 10:36:56 +0000 (UTC), Lutz Donnerhacke >>>How about a fixing rule, which applies at the private syntax element? >> >> Which rule do you mean? > >If publicly defined tagged types are fixed at the private syntax element, >there is no possibility to define dispatching procedures and functions >afterwards. Of course, it's not a choice, because it will break existing >programs. But what if I need to extend the interface by adding some new primitive operations? Or do you mean some sort of interface freezing like Java's "final"? It will face same problems to be solved: package A is type X is tagged ...; procedure Foo (Obj : X); end A; package B is type XX is new X with ...; procedure Foo (Obj : XX) is final; -- No more overridings end B; package C is type Y is new X with private; procedure Foo (Obj : Y); -- Going to override, can I? private type Y is new XX with ...; -- Oops, I can't! end C; I can only repeat my old thesis: either multiple inheritance allows a reasonable implementation, or there should be no inheritance at all. --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-22 14:46 ` Dmitry A. Kazakov @ 2003-07-22 15:11 ` Lutz Donnerhacke 2003-07-23 8:12 ` Dmitry A. Kazakov 0 siblings, 1 reply; 35+ messages in thread From: Lutz Donnerhacke @ 2003-07-22 15:11 UTC (permalink / raw) * Dmitry A Kazakov wrote: > On Tue, 22 Jul 2003 12:18:57 +0000 (UTC), Lutz Donnerhacke >>If publicly defined tagged types are fixed at the private syntax element, >>there is no possibility to define dispatching procedures and functions >>afterwards. Of course, it's not a choice, because it will break existing >>programs. > > But what if I need to extend the interface by adding some new > primitive operations? Not possible in the private part. Plain and simple. package X is type T is tagged private; function Foo return T; -- Ok. private -- fix T procedure Bar(o : T); -- Fails. type T is new Ada.Finalization.Controlled with null record; -- Fails. end X; but package X is type T is tagged private; function Foo return T; private -- fix T type T is ... end X; with X; package Y is type T is new X.T with private; procedure Bar(o : T); -- Ok. private type T is new X.T with null record; end Y; with X; package Z is [...] private type T is new X.T with null record; procedure Bar(o : T); -- Ok. end Z; > Or do you mean some sort of interface freezing like Java's "final"? No. ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-22 15:11 ` Lutz Donnerhacke @ 2003-07-23 8:12 ` Dmitry A. Kazakov 0 siblings, 0 replies; 35+ messages in thread From: Dmitry A. Kazakov @ 2003-07-23 8:12 UTC (permalink / raw) On Tue, 22 Jul 2003 15:11:15 +0000 (UTC), Lutz Donnerhacke <lutz@iks-jena.de> wrote: >* Dmitry A Kazakov wrote: >> On Tue, 22 Jul 2003 12:18:57 +0000 (UTC), Lutz Donnerhacke >>>If publicly defined tagged types are fixed at the private syntax element, >>>there is no possibility to define dispatching procedures and functions >>>afterwards. Of course, it's not a choice, because it will break existing >>>programs. >> >> But what if I need to extend the interface by adding some new >> primitive operations? > >Not possible in the private part. Plain and simple. > >package X is > type T is tagged private; > function Foo return T; -- Ok. >private -- fix T > procedure Bar(o : T); -- Fails. > type T is new Ada.Finalization.Controlled with null record; -- Fails. >end X; But I do need private primitive operations to implement T and note, to reuse them while implementing the types derived from T. This proposal in effect would make impossible to have both public and private operations. This will force a type designer to publish everything breaking information hiding. Just ask the question, why type T is new Ada.Finalization.Controlled with null record; was made private? The only answer is: to hide Initialize/Finalize! To my taste even 3.9.3(10) is too limiting. It should be possible to declare a private abstract primitive subprogram! For example: type T is private abstract tagged private; -- (:-)) private type T is abstract tagged ...; procedure Write_etc_passwd (This : T) is abstract; You can derive from T only in a child package. The public declaration of T shall specify this fact, of course. --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-18 20:26 ` Robert I. Eachus 2003-07-18 21:35 ` tmoran @ 2003-07-19 14:44 ` Chad R. Meiners 2003-07-20 12:36 ` Robert I. Eachus 1 sibling, 1 reply; 35+ messages in thread From: Chad R. Meiners @ 2003-07-19 14:44 UTC (permalink / raw) "Robert I. Eachus" <rieachus@attbi.com> wrote in message news:3F1857E4.60702@attbi.com... > At least GNAT agrees with me. ;-) Seriously I think that Tucker may be > correct, "by the book." But to not be able to declare Leaf.Initialize > as overriding defeats the whole point. Sigh. So now even if we adopt > my solution or the new syntax, we still have to change 7.3.1 to get the > definition of overriding to agree with the (to me) commonsense definition. Well one problem is that some people (as in me) think that Tucker's behavior is common sense. Although either way, it is best to have the compilers agree ;) -CRM ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-19 14:44 ` Chad R. Meiners @ 2003-07-20 12:36 ` Robert I. Eachus 0 siblings, 0 replies; 35+ messages in thread From: Robert I. Eachus @ 2003-07-20 12:36 UTC (permalink / raw) Chad R. Meiners wrote: > Well one problem is that some people (as in me) think that Tucker's behavior > is common sense. Although either way, it is best to have the compilers agree > ;) On most every issue debated in the ARG, the actual decision made is almost a detail. The important parts are to make sure that everyone understands the issue, that we don't create new issues when fixing a current one, and to cover all cases. I personally think that the effort needed to allow support two dispatching operations of the same name, and which one gets called depends on the place in the text of the call is unnecessary overhead. (Note that having several dispatching operations with the same name, and determining which is called by a view conversion is clearly necessary. The surprise in this case is that there is no view conversion needed.) But again, any case where this comes up is expected to be one where the user is unintentionally shooting himself in the foot. The intent of adding pragma Overriding or the overriding keyword is to allow the user to detect such cases at compile time. THAT is the important part of the AI. This particular example arose when I was demonstrating that there are cases of overriding where there would be no reasonable place to put the pragma or keyword. It turned out that in this particular case, I was right to be wrong. I understood the rules the way GNAT implements them, while others compilers do it differently. I think that the final resolution will be to read things the way Tuck was arguing, with possibly a few "extra" words to insure that the only cases where the dual meanings arise are in package specs. I don't think we want a Beaujolais-like effect, where adding a with clause can change which version gets called. -- Robert I. Eachus �In an ally, considerations of house, clan, planet, race are insignificant beside two prime questions, which are: 1. Can he shoot? 2. Will he aim at your enemy?� -- from the Laiden novels by Sharon Lee and Steve Miller. ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-11 8:22 Q: Endless loop by dispatching Michael Erdmann 2003-07-11 9:46 ` Jean-Pierre Rosen 2003-07-11 10:01 ` Q: " Dmitry A. Kazakov @ 2003-07-11 16:27 ` T. Kurt Bond 2003-07-12 8:37 ` Michael Erdmann 2 siblings, 1 reply; 35+ messages in thread From: T. Kurt Bond @ 2003-07-11 16:27 UTC (permalink / raw) -- Michael Erdmann <michael.erdmann@snafu.de> asked in message -- news:<un82u-4kb.ln1@boavista.snafu.de> about redispatching on 'Class types, -- which was causing his program to loop endlessly. -- -- Here's a program that includes his example code and does what (I think) -- he wants. -- with Ada.Text_IO; use Ada.Text_IO; procedure Test is -- From: Michael Erdmann <michael.erdmann@snafu.de> -- Subject: Q: Endless loop by dispatching -- Newsgroups: comp.lang.ada -- Date: Fri, 11 Jul 2003 10:22:54 +0200 -- Organization: [Posted via] Inter.net Germany GmbH -- Dear all, -- i got a problem with the following code fragment below. The Idea is -- that the procedure Serialize defines the strategy how to display -- object which -- are derived from A.Object. Searialize simply dispatches into the class -- by calling a procedure Write, which does the job for the class. package A is type Object is tagged record P1 : Natural := 1; P2 : Natural := 2; end record; type Class_Access is access Object'Class; -- added for example. procedure Write(This : in Object ); procedure Serialize(This : in Object'Class ); end A; package body A is procedure Serialize(This : in Object'Class ) is begin Put_Line ("Serialize (Object'Class) called:"); -- added for example Write( A.Object (This) ); -- changed for example!!! -- Since "This" is at Object'Class, "Write (This)" would dispatch -- on the actual tag of "This", calling "B.Write" for objects of -- type "B.Object", which would call "A.Serialize" again, -- looping forever. To always call A.Write, construct -- a *view* of the object as being of type "A.object" by using the -- *view conversion* "A.Object(This)". end Serialize; procedure Write(This : in Object ) is begin Put_Line ("Write (A.Object) called:"); -- added for example Put_Line( "P1 =" & Natural'Image( This.P1 ) ); Put_Line( "P2 =" & Natural'Image( This.P2 ) ); end Write; end A; -- In the following fragment i am defining a package B with an -- derived objec B.Object as below. When an instance of B.Object -- shall be serialized, the element of the super class (A.Object) -- shall be serialzed as well. The code looks nice and compiles -- but does not work, since the Serialize dispatches again with -- Object.B even ther was a a case given A.Object( This ). package B is type Object is new A.Object with record Q : Natural := 2; end record; procedure Write(This : in Object ); end B; -- .......... package body B is procedure Write(This : in Object ) is begin Put_Line ("Write (B.Object) called:"); A.Serialize( A.Object( This ) ); Put_Line( "Q =" & Natural'Image(This.Q)); end Write; end B; -- Does any body know, what this loop causes?! I am not sure -- if this is a bug or simply i missed the point. -- Michael Aobj : A.Object; Bobj : B.Object; Objs : array (1 .. 4) of A.Class_Access := (new A.Object, new B.Object, new A.Object, new B.Object); begin Put_Line ("Write A"); A.Write (Aobj); New_Line; Put_Line ("Write B"); B.Write (Bobj); New_Line; Put_Line ("Dispatching calls:"); for I in Objs'Range loop Put_Line ("A.Write (Objs(" & Integer'Image (I) & "))"); -- This will dispatch, so B.Write will actually be called -- for Objs(2) and Objs(3) A.Write (Objs (I).all); end loop; end Test; -- The preceding program produces the following output when run: -- Write A -- Write (A.Object) called: -- P1 = 1 -- P2 = 2 -- -- Write B -- Write (B.Object) called: -- Serialize (Object'Class) called: -- Write (A.Object) called: -- P1 = 1 -- P2 = 2 -- Q = 2 -- -- Dispatching calls: -- A.Write (Objs( 1)) -- Write (A.Object) called: -- P1 = 1 -- P2 = 2 -- A.Write (Objs( 2)) -- Write (B.Object) called: -- Serialize (Object'Class) called: -- Write (A.Object) called: -- P1 = 1 -- P2 = 2 -- Q = 2 -- A.Write (Objs( 3)) -- Write (A.Object) called: -- P1 = 1 -- P2 = 2 -- A.Write (Objs( 4)) -- Write (B.Object) called: -- Serialize (Object'Class) called: -- Write (A.Object) called: -- P1 = 1 -- P2 = 2 -- Q = 2 ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-11 16:27 ` T. Kurt Bond @ 2003-07-12 8:37 ` Michael Erdmann 2003-07-15 7:11 ` Kenneth Almquist 0 siblings, 1 reply; 35+ messages in thread From: Michael Erdmann @ 2003-07-12 8:37 UTC (permalink / raw) To: T. Kurt Bond T. Kurt Bond wrote: Thanks. In fact i have now selected this aproach. Each package derives from the base type (A.Object) is forced to implement a procedure Serialize by definint it in A as abstract. The bad thing about it, is that i wanted to add some code which is common to all implementation of A.Object in the Central Serialize procedure (e.g. writing the attrbiute name if ront of every field of B.Object) Now i have to duplicate this code in all implementations of A.Object. Some time i am realy wondering if there is something like Serialize( Super(This) ...) is missing, which is realy the tag of the superclass of B.Object. Thanks Michael > -- Michael Erdmann <michael.erdmann@snafu.de> asked in message > -- news:<un82u-4kb.ln1@boavista.snafu.de> about redispatching on 'Class types, > -- which was causing his program to loop endlessly. > -- > -- Here's a program that includes his example code and does what (I think) > -- he wants. > -- > with Ada.Text_IO; use Ada.Text_IO; > procedure Test is > -- From: Michael Erdmann <michael.erdmann@snafu.de> > -- Subject: Q: Endless loop by dispatching > -- Newsgroups: comp.lang.ada > -- Date: Fri, 11 Jul 2003 10:22:54 +0200 > -- Organization: [Posted via] Inter.net Germany GmbH > > -- Dear all, > > -- i got a problem with the following code fragment below. The Idea is > -- that the procedure Serialize defines the strategy how to display > -- object which > -- are derived from A.Object. Searialize simply dispatches into the class > -- by calling a procedure Write, which does the job for the class. > package A is > type Object is tagged record > P1 : Natural := 1; > P2 : Natural := 2; > end record; > type Class_Access is access Object'Class; -- added for example. > > procedure Write(This : in Object ); > procedure Serialize(This : in Object'Class ); > end A; > > package body A is > procedure Serialize(This : in Object'Class ) is > begin > Put_Line ("Serialize (Object'Class) called:"); -- added for example > Write( A.Object (This) ); -- changed for example!!! > -- Since "This" is at Object'Class, "Write (This)" would dispatch > -- on the actual tag of "This", calling "B.Write" for objects of > -- type "B.Object", which would call "A.Serialize" again, > -- looping forever. To always call A.Write, construct > -- a *view* of the object as being of type "A.object" by using the > -- *view conversion* "A.Object(This)". > end Serialize; > > procedure Write(This : in Object ) is > begin > Put_Line ("Write (A.Object) called:"); -- added for example > Put_Line( "P1 =" & Natural'Image( This.P1 ) ); > Put_Line( "P2 =" & Natural'Image( This.P2 ) ); > end Write; > end A; > > -- In the following fragment i am defining a package B with an > -- derived objec B.Object as below. When an instance of B.Object > -- shall be serialized, the element of the super class (A.Object) > -- shall be serialzed as well. The code looks nice and compiles > -- but does not work, since the Serialize dispatches again with > -- Object.B even ther was a a case given A.Object( This ). > > package B is > type Object is new A.Object with record > Q : Natural := 2; > end record; > > procedure Write(This : in Object ); > end B; > -- .......... > package body B is > procedure Write(This : in Object ) is > begin > Put_Line ("Write (B.Object) called:"); > A.Serialize( A.Object( This ) ); > Put_Line( "Q =" & Natural'Image(This.Q)); > end Write; > end B; > > -- Does any body know, what this loop causes?! I am not sure > -- if this is a bug or simply i missed the point. > > -- Michael > > Aobj : A.Object; > Bobj : B.Object; > Objs : array (1 .. 4) of A.Class_Access := > (new A.Object, new B.Object, new A.Object, new B.Object); > begin > Put_Line ("Write A"); > A.Write (Aobj); > New_Line; > Put_Line ("Write B"); > B.Write (Bobj); > New_Line; > Put_Line ("Dispatching calls:"); > for I in Objs'Range loop > Put_Line ("A.Write (Objs(" & Integer'Image (I) & "))"); > -- This will dispatch, so B.Write will actually be called > -- for Objs(2) and Objs(3) > A.Write (Objs (I).all); > end loop; > end Test; > > -- The preceding program produces the following output when run: > -- Write A > -- Write (A.Object) called: > -- P1 = 1 > -- P2 = 2 > -- > -- Write B > -- Write (B.Object) called: > -- Serialize (Object'Class) called: > -- Write (A.Object) called: > -- P1 = 1 > -- P2 = 2 > -- Q = 2 > -- > -- Dispatching calls: > -- A.Write (Objs( 1)) > -- Write (A.Object) called: > -- P1 = 1 > -- P2 = 2 > -- A.Write (Objs( 2)) > -- Write (B.Object) called: > -- Serialize (Object'Class) called: > -- Write (A.Object) called: > -- P1 = 1 > -- P2 = 2 > -- Q = 2 > -- A.Write (Objs( 3)) > -- Write (A.Object) called: > -- P1 = 1 > -- P2 = 2 > -- A.Write (Objs( 4)) > -- Write (B.Object) called: > -- Serialize (Object'Class) called: > -- Write (A.Object) called: > -- P1 = 1 > -- P2 = 2 > -- Q = 2 ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: Q: Endless loop by dispatching 2003-07-12 8:37 ` Michael Erdmann @ 2003-07-15 7:11 ` Kenneth Almquist 0 siblings, 0 replies; 35+ messages in thread From: Kenneth Almquist @ 2003-07-15 7:11 UTC (permalink / raw) Michael Erdmann <michael.erdmann@snafu.de> wrote: > Thanks. In fact i have now selected this aproach. Each package > derives from the base type (A.Object) is forced to implement > a procedure Serialize by definint it in A as abstract. > > The bad thing about it, is that i wanted to add some code > which is common to all implementation of A.Object in the > Central Serialize procedure (e.g. writing the attrbiute > name if ront of every field of B.Object) Now i have to duplicate > this code in all implementations of A.Object. The way to avoid duplicate code is to place the code in a generic procedure which is instantiated for each type. Something along the line of: package A is type Object is tagged private; -- Write out all of the attributes of an object. procedure Serialize(This : Object); -- Write the value of a single attribute. procedure Write(This : Object; Attribute : Attribute_Id); -- Serialize_Extension for type T writes the attributes -- which appear in T type but not in the parent of type T. generic type T is new Object with private; Attributes : in Attribute_Array; with procedure Write(This : Object; Attribute : Integer) is <>; procedure Serialize_Extension(This : Object); end A; package B is type Object is new A.Object with private; -- Write out all of the attributes of an object. procedure Serialize(This : Object); -- Write the value of a single attribute. procedure Write(This : Object; Attribute : Attribute_Id); end B; package body B is My_Attributes : constant Attribute_Array := (...); procedure Serialize(This : Object) is procedure SE is new Serialize_Extension(Object, My_Attributes); begin Serialize(A.Object(This)); SE(This); end Serialize; procedure Write(This : Object; Attribute : Attribute_Id) is ...; end B; Kenneth Almquist ^ permalink raw reply [flat|nested] 35+ messages in thread
end of thread, other threads:[~2003-07-23 8:12 UTC | newest] Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2003-07-11 8:22 Q: Endless loop by dispatching Michael Erdmann 2003-07-11 9:46 ` Jean-Pierre Rosen 2003-07-11 15:19 ` Michael Erdmann 2003-07-11 10:01 ` Q: " Dmitry A. Kazakov 2003-07-11 15:07 ` Michael Erdmann 2003-07-12 1:41 ` Jeffrey Carter 2003-07-14 8:48 ` Dmitry A. Kazakov 2003-07-14 18:38 ` Randy Brukardt 2003-07-15 8:47 ` Dmitry A. Kazakov 2003-07-15 17:23 ` Randy Brukardt 2003-07-16 8:08 ` Dmitry A. Kazakov 2003-07-16 17:44 ` Robert I. Eachus 2003-07-17 1:57 ` Robert A Duff 2003-07-18 9:10 ` Dale Stanbrough 2003-07-18 20:26 ` Robert I. Eachus 2003-07-18 21:35 ` tmoran 2003-07-19 0:25 ` Robert I. Eachus 2003-07-19 2:30 ` tmoran 2003-07-19 5:48 ` Robert I. Eachus 2003-07-21 8:38 ` Dmitry A. Kazakov 2003-07-21 10:08 ` Robert I. Eachus 2003-07-21 13:21 ` Dmitry A. Kazakov 2003-07-21 18:51 ` Robert I. Eachus 2003-07-22 7:41 ` Dmitry A. Kazakov 2003-07-22 10:36 ` Lutz Donnerhacke 2003-07-22 12:11 ` Dmitry A. Kazakov 2003-07-22 12:18 ` Lutz Donnerhacke 2003-07-22 14:46 ` Dmitry A. Kazakov 2003-07-22 15:11 ` Lutz Donnerhacke 2003-07-23 8:12 ` Dmitry A. Kazakov 2003-07-19 14:44 ` Chad R. Meiners 2003-07-20 12:36 ` Robert I. Eachus 2003-07-11 16:27 ` T. Kurt Bond 2003-07-12 8:37 ` Michael Erdmann 2003-07-15 7:11 ` Kenneth Almquist
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox