* tagged type as generic parameter @ 2008-01-03 15:20 Philippe Tarroux 2008-01-03 15:51 ` Dmitry A. Kazakov 0 siblings, 1 reply; 14+ messages in thread From: Philippe Tarroux @ 2008-01-03 15:20 UTC (permalink / raw) Hi everybody, I wrote the following packages: generic type Data is tagged private; -- In order to be able to build lists of items of this type package List is type List (<>) is private; private type Item; type Item_Ptr is access Item; type Item is new Data with record -- Line 22 Next : Item_Ptr; end record; type List_Head is tagged record Head : Item_Ptr := null; end record; type List is access List_Head; end List; ----------------------------------- package data_handler is type Data is tagged private; function A_Data(V : Integer) return Data; procedure Print (D : Data); private type Data is tagged record Value : Integer; end record; end data_handler; ------------------------------------------- with List; with Data_Handler; use Data_Handler; package data_list is package My_List is new List (Data_Handler.Donn�es); end data_list; When i try to instantiate the last package (data_list) i get the following error: data_list.ads:7:04: instantiation error at list.ads:22 data_list.ads:7:04: type must be declared abstract or "a_data" overridden data_list.ads:7:04: "a_data" has been inherited at list.ads:22, instance at line 7 data_list.ads:7:04: "a_data" has been inherited from subprogram at data_handler.ads:5 I suspect the problem is due to the derivation of Item from Data at line 22 of list.ads during the instantiation of the generic but I don't really understand why and i don't understand why the problem arises with the function A_Data and not with the procedure Print. OS : W2K GCC version 4.1.3 20070403 for GNAT GPL 2007 Thank and best regards Philippe Tarroux ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: tagged type as generic parameter 2008-01-03 15:20 tagged type as generic parameter Philippe Tarroux @ 2008-01-03 15:51 ` Dmitry A. Kazakov 2008-01-03 16:22 ` Adam Beneschan 2008-01-04 13:08 ` Philippe Tarroux 0 siblings, 2 replies; 14+ messages in thread From: Dmitry A. Kazakov @ 2008-01-03 15:51 UTC (permalink / raw) On Thu, 03 Jan 2008 16:20:48 +0100, Philippe Tarroux wrote: > I wrote the following packages: > > generic > type Data is tagged private; -- In order to be able to build lists > of items of this type > package List is > > type List (<>) is private; > > private > type Item; > type Item_Ptr is access Item; > type Item is new Data with record -- Line 22 > Next : Item_Ptr; > end record; > > type List_Head is tagged record > Head : Item_Ptr := null; > end record; > > type List is access List_Head; > end List; > > ----------------------------------- > package data_handler is > > type Data is tagged private; > > function A_Data(V : Integer) return Data; > procedure Print (D : Data); > > private > > type Data is tagged record > Value : Integer; > end record; > > end data_handler; [...] > I suspect the problem is due to the derivation of Item from Data at line > 22 of list.ads during the instantiation of the generic but I don't > really understand why and i don't understand why the problem arises with > the function A_Data and not with the procedure Print. The function A_Data returns Data. It is a primitive operation of Data and thus covariant in the result. So when you derive anything from Data, you have to override it in order to provide a correct implementation that would return the derived type rather than the base. There are many ways to resolve the issue, the choice depends on other factors: 1. Class-wide A_Data: function A_Data (V : Integer) return Data'Class; This will be same (contravariant) for all descendants of A_Data and thus need not to overridden. 2. Data-specific List package: generic type Data is abstract new Data_Handler.Data with private; package Data_List is ... type Item is new Data with record Next : Item_Ptr; end record; function A_Data (V : Integer) return Item; We know here that Data is a descendant of Data_Handler.Data, so we can provide an override for A_Data. 3. Aggregation instead of inheritance: type Item is record Next : Item_Ptr; Value : Data; end record; No inheritance, no problem. 4. Non-generic implementation of lists. You can define a list interface and derive Data_Handler.Data from a list item. (In Ada 2005 it is easier to do than it was in Ada 95) That would reverse the inheritance order and thus solve the problem with A_Data. 5. Storage-pool based implementation of lists. You can design a storage pool that would maintain lists of allocated there items. In this case, unlikely to all other variants, the list item is not a fully separate type but just a pool-specific access to Data type. Because there again is no inheritance involved, the problem is solved. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: tagged type as generic parameter 2008-01-03 15:51 ` Dmitry A. Kazakov @ 2008-01-03 16:22 ` Adam Beneschan 2008-01-03 16:58 ` Dmitry A. Kazakov 2008-01-04 13:08 ` Philippe Tarroux 1 sibling, 1 reply; 14+ messages in thread From: Adam Beneschan @ 2008-01-03 16:22 UTC (permalink / raw) On Jan 3, 7:51 am, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> wrote: > 3. Aggregation instead of inheritance: > > type Item is record > Next : Item_Ptr; > Value : Data; > end record; > > No inheritance, no problem. Actually, I think the OP really needs a darn good reason why he would want Item to be inherited from his generic formal type, rather than simply a record containing a value and a link as in your above suggestion. Conceptually, at least to me, a type extension is supposed to define a type that is a "kind of" the parent type. In this case, Item, as the OP originally defined it, doesn't really fit the concept. It's not really a "kind of" Data with additional properties. I'm sorry that my "pedagogical" understanding of object- oriented programming isn't solid enough that I understand what terms to use, but hopefully I'm getting some sort of notion across. Or, to put it another way, don't use type extensions just because they're there. To me, #3 stands out as the *correct* solution to the problem, in most cases. Plus, if you do that, Data no longer needs to be a tagged formal type, so that you can use your generic on both tagged and untagged types. -- Adam ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: tagged type as generic parameter 2008-01-03 16:22 ` Adam Beneschan @ 2008-01-03 16:58 ` Dmitry A. Kazakov 2008-01-03 17:47 ` Jean-Pierre Rosen 0 siblings, 1 reply; 14+ messages in thread From: Dmitry A. Kazakov @ 2008-01-03 16:58 UTC (permalink / raw) On Thu, 3 Jan 2008 08:22:24 -0800 (PST), Adam Beneschan wrote: > On Jan 3, 7:51 am, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> > wrote: > >> 3. Aggregation instead of inheritance: >> >> type Item is record >> Next : Item_Ptr; >> Value : Data; >> end record; >> >> No inheritance, no problem. > > Actually, I think the OP really needs a darn good reason why he would > want Item to be inherited from his generic formal type, rather than > simply a record containing a value and a link as in your above > suggestion. Conceptually, at least to me, a type extension is > supposed to define a type that is a "kind of" the parent type. In > this case, Item, as the OP originally defined it, doesn't really fit > the concept. It's not really a "kind of" Data with additional > properties. I'm sorry that my "pedagogical" understanding of object- > oriented programming isn't solid enough that I understand what terms > to use, but hopefully I'm getting some sort of notion across. A reason might be to be able to use list items and their content interchangeably, another could be to handle unconstrained data. However, these are certainly not the case for the OP's code. Because Item is private there and Data is constrained. And even if Item were visible, then the right way would likely be #2, because "anything tagged" as in OP's code does not tell much about the inherited semantics of list elements. IMO, your understanding of OOP is quite right. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: tagged type as generic parameter 2008-01-03 16:58 ` Dmitry A. Kazakov @ 2008-01-03 17:47 ` Jean-Pierre Rosen 2008-01-03 18:13 ` Pascal Obry ` (2 more replies) 0 siblings, 3 replies; 14+ messages in thread From: Jean-Pierre Rosen @ 2008-01-03 17:47 UTC (permalink / raw) Dmitry A. Kazakov a �crit : > However, these are certainly not the case for the OP's code. Because Item > is private there and Data is constrained. And even if Item were visible, > then the right way would likely be #2, because "anything tagged" as in OP's > code does not tell much about the inherited semantics of list elements. > > IMO, your understanding of OOP is quite right. > Yeap. In these times where everybody is talking about OOP, people tend to move from "everything can be done with inheritance" to "everything must be done with inheritance". To be honnest, some languages offer inheritance as the only way, so there is no choice. When you are lucky enough to have a language that supports multiple paradigms, composition has its value. -- --------------------------------------------------------- J-P. Rosen (rosen@adalog.fr) Visit Adalog's web site at http://www.adalog.fr ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: tagged type as generic parameter 2008-01-03 17:47 ` Jean-Pierre Rosen @ 2008-01-03 18:13 ` Pascal Obry 2008-01-03 19:20 ` Dmitry A. Kazakov 2008-01-03 21:37 ` Jeffrey R. Carter 2 siblings, 0 replies; 14+ messages in thread From: Pascal Obry @ 2008-01-03 18:13 UTC (permalink / raw) To: Jean-Pierre Rosen Jean-Pierre Rosen a �crit : > When you are lucky enough to have a language that supports multiple > paradigms, composition has its value. I fully agree. There is some very wrong use of inheritance those days. Pascal. -- --|------------------------------------------------------ --| Pascal Obry Team-Ada Member --| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE --|------------------------------------------------------ --| http://www.obry.net --| "The best way to travel is by means of imagination" --| --| gpg --keyserver wwwkeys.pgp.net --recv-key C1082595 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: tagged type as generic parameter 2008-01-03 17:47 ` Jean-Pierre Rosen 2008-01-03 18:13 ` Pascal Obry @ 2008-01-03 19:20 ` Dmitry A. Kazakov 2008-01-03 21:37 ` Jeffrey R. Carter 2 siblings, 0 replies; 14+ messages in thread From: Dmitry A. Kazakov @ 2008-01-03 19:20 UTC (permalink / raw) On Thu, 03 Jan 2008 18:47:12 +0100, Jean-Pierre Rosen wrote: > To be honnest, some languages offer > inheritance as the only way, so there is no choice. There is nothing automatically wrong in doing aggregation per inheritance if one can hide undesired side effects in public interfaces: type Container is private; private type Container is new Contained...; I can imagine Ada without built-in record types, but with record interfaces implemented via privately made multiple inheritance. One can always escape the base type class in Ada by deriving privately. Unfortunately "type X is new Y" does not work for tagged types. Otherwise it would be even better. Important to me is consistency of the language design preventing suspicious code from being compiled. It did not compile because in Ada: 1. Generics are contracted; 2. Primitive operations are ones in all arguments and the result; 3. Private does not leak. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: tagged type as generic parameter 2008-01-03 17:47 ` Jean-Pierre Rosen 2008-01-03 18:13 ` Pascal Obry 2008-01-03 19:20 ` Dmitry A. Kazakov @ 2008-01-03 21:37 ` Jeffrey R. Carter 2008-01-04 13:08 ` Philippe Tarroux 2 siblings, 1 reply; 14+ messages in thread From: Jeffrey R. Carter @ 2008-01-03 21:37 UTC (permalink / raw) Jean-Pierre Rosen wrote: > Yeap. In these times where everybody is talking about OOP, people tend > to move from "everything can be done with inheritance" to "everything > must be done with inheritance". To be honnest, some languages offer > inheritance as the only way, so there is no choice. Given the OP's comment that the formal is tagged so that he will be able to build lists of the type implies that he comes from a background in such a language. > When you are lucky enough to have a language that supports multiple > paradigms, composition has its value. I agree. Programming by extension, emphasizing, as it does, ease of writing over ease of reading, should be avoided whenever possible by SW engineers, and used with the same reluctance and care that they give to gotos and access types. -- Jeff Carter "Have you gone berserk? Can't you see that that man is a ni?" Blazing Saddles 38 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: tagged type as generic parameter 2008-01-03 21:37 ` Jeffrey R. Carter @ 2008-01-04 13:08 ` Philippe Tarroux 2008-01-04 15:03 ` Jean-Pierre Rosen 0 siblings, 1 reply; 14+ messages in thread From: Philippe Tarroux @ 2008-01-04 13:08 UTC (permalink / raw) Jeffrey R. Carter a �crit : > Jean-Pierre Rosen wrote: >> Yeap. In these times where everybody is talking about OOP, people >> tend to move from "everything can be done with inheritance" to >> "everything must be done with inheritance". To be honnest, some >> languages offer inheritance as the only way, so there is no choice. > > Given the OP's comment that the formal is tagged so that he will be > able to build lists of the type implies that he comes from a > background in such a language. What i wanted is not the "best" way to implement lists. I just wanted to explore this way. The strong OOP orientation is due to the fact that i tried this example after a discussion with one of my student arguing that Ada is too complex compared to Java. I wanted to explore '� la Java' solutions. > >> When you are lucky enough to have a language that supports multiple >> paradigms, composition has its value. I agree too. Philippe Tarroux ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: tagged type as generic parameter 2008-01-04 13:08 ` Philippe Tarroux @ 2008-01-04 15:03 ` Jean-Pierre Rosen 0 siblings, 0 replies; 14+ messages in thread From: Jean-Pierre Rosen @ 2008-01-04 15:03 UTC (permalink / raw) Philippe Tarroux a �crit : >> Given the OP's comment that the formal is tagged so that he will be >> able to build lists of the type implies that he comes from a >> background in such a language. > What i wanted is not the "best" way to implement lists. I just wanted to > explore this way. The strong OOP orientation is due to the fact that i > tried this example after a discussion with one of my student arguing > that Ada is too complex compared to Java. I wanted to explore '� la > Java' solutions. Of course, '� la Java' solutions coded in Ada will always be disadvantaged; the converse is also true. When discussing language complexity, I think you should start from a real problem (without overspecification!), code it in each language following each language's philosophy, and compare the result. Everything else is biased. -- --------------------------------------------------------- J-P. Rosen (rosen@adalog.fr) Visit Adalog's web site at http://www.adalog.fr ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: tagged type as generic parameter 2008-01-03 15:51 ` Dmitry A. Kazakov 2008-01-03 16:22 ` Adam Beneschan @ 2008-01-04 13:08 ` Philippe Tarroux 2008-01-04 13:22 ` Georg Bauhaus 2008-01-04 14:17 ` Dmitry A. Kazakov 1 sibling, 2 replies; 14+ messages in thread From: Philippe Tarroux @ 2008-01-04 13:08 UTC (permalink / raw) Dmitry A. Kazakov a �crit : > > The function A_Data returns Data. It is a primitive operation of Data and > thus covariant in the result. So when you derive anything from Data, you > have to override it in order to provide a correct implementation that would > return the derived type rather than the base. > Ok. But does it mean that only the constructor is a primitive operation of the data type, not the print procedure? In this case why Print doesn't need to be redefined? > There are many ways to resolve the issue, the choice depends on other > factors: > > 1. Class-wide A_Data: > > function A_Data (V : Integer) return Data'Class; > > This will be same (contravariant) for all descendants of A_Data and thus > need not to overridden. > > 2. Data-specific List package: > > generic > type Data is abstract new Data_Handler.Data with private; > package Data_List is > ... > type Item is new Data with record > Next : Item_Ptr; > end record; > function A_Data (V : Integer) return Item; > > We know here that Data is a descendant of Data_Handler.Data, so we can > provide an override for A_Data. > > 3. Aggregation instead of inheritance: > > type Item is record > Next : Item_Ptr; > Value : Data; > end record; > > No inheritance, no problem. > > 4. Non-generic implementation of lists. You can define a list interface and > derive Data_Handler.Data from a list item. (In Ada 2005 it is easier to do > than it was in Ada 95) That would reverse the inheritance order and thus > solve the problem with A_Data. > > 5. Storage-pool based implementation of lists. You can design a storage > pool that would maintain lists of allocated there items. In this case, > unlikely to all other variants, the list item is not a fully separate type > but just a pool-specific access to Data type. Because there again is no > inheritance involved, the problem is solved. > Thanks for all these suggestions that bring to me interesting insights. Especially i know that #4 solves the problem (it is the alternative proposed in Barnes for the construction of list items). I won't be aware of #5. I will try it. Regards Philippe Tarroux ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: tagged type as generic parameter 2008-01-04 13:08 ` Philippe Tarroux @ 2008-01-04 13:22 ` Georg Bauhaus 2008-01-04 15:38 ` Philippe Tarroux 2008-01-04 14:17 ` Dmitry A. Kazakov 1 sibling, 1 reply; 14+ messages in thread From: Georg Bauhaus @ 2008-01-04 13:22 UTC (permalink / raw) On Fri, 2008-01-04 at 14:08 +0100, Philippe Tarroux wrote: > Dmitry A. Kazakov a écrit : > > > > The function A_Data returns Data. It is a primitive operation of Data and > > thus covariant in the result. So when you derive anything from Data, you > > have to override it in order to provide a correct implementation that would > > return the derived type rather than the base. > > > Ok. But does it mean that only the constructor is a primitive operation > of the data type, not the print procedure? In this case why Print > doesn't need to be redefined? Data's Print operation works for objects of any type rooted at Data. There is always a Data view of such an object. OTOH, a function that is to return an object of a type derived from Data will have to provide all components of the derived type. That's not the LRM reason for the need to override the function. But it should be a hint as to why this need exists (the variance issue Dmitry has mentioned). Imagine this Data function make (...) return Data; ^ | -- inheritance, IS A Special_Data When you have a variable V of type Special_Data and you call V := make (...); then---without an overridden make---this Make would have to be the Make defined with type Data. However, the Make defined with Data cannot return objects of type Special_Data, which is needed. OTOH, When you have a variable V of type Special_Data and you call print(V); there is no problem because Print works with Data objects and V "IS A" Data object (its type is derived from Data.) So Print views V as being of type Data, not Special_Data, in a sense. HTH, Georg ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: tagged type as generic parameter 2008-01-04 13:22 ` Georg Bauhaus @ 2008-01-04 15:38 ` Philippe Tarroux 0 siblings, 0 replies; 14+ messages in thread From: Philippe Tarroux @ 2008-01-04 15:38 UTC (permalink / raw) Georg Bauhaus a écrit : > On Fri, 2008-01-04 at 14:08 +0100, Philippe Tarroux wrote: > >> Dmitry A. Kazakov a écrit : >> >>> The function A_Data returns Data. It is a primitive operation of Data and >>> thus covariant in the result. So when you derive anything from Data, you >>> have to override it in order to provide a correct implementation that would >>> return the derived type rather than the base. >>> >>> >> Ok. But does it mean that only the constructor is a primitive operation >> of the data type, not the print procedure? In this case why Print >> doesn't need to be redefined? >> > > Data's Print operation works for objects of any type rooted at > Data. There is always a Data view of such an object. > > OTOH, a function that is to return an object of a type > derived from Data will have to provide all components > of the derived type. That's not the LRM reason for the need > to override the function. But it should be a hint as to > why this need exists (the variance issue Dmitry has mentioned). > > Imagine this > > Data > function make (...) return Data; > ^ > | -- inheritance, IS A > Special_Data > > > When you have a variable V of type Special_Data > and you call > > V := make (...); > > then---without an overridden make---this Make would have to be > the Make defined with type Data. However, the Make defined > with Data cannot return objects of type Special_Data, which > is needed. > > OTOH, When you have a variable V of type Special_Data > and you call > > print(V); > > there is no problem because Print works with Data > objects and V "IS A" Data object (its type is derived > from Data.) So Print views V as being of type Data, > not Special_Data, in a sense. > > HTH, Georg > > Thanks for your explanations. That's all clear for me now. I have missed this point which is similar to the one raised in Barnes about Geometry.Triangles. He suggests that a way to avoid the redefinition of the constructor when there is no need of it or when the constructor of the derived type hasn't the same structure of parameters, is to use a child function. In this case the function is not a primitive operation of the type. I am going to look if it can apply to the present case. Philippe ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: tagged type as generic parameter 2008-01-04 13:08 ` Philippe Tarroux 2008-01-04 13:22 ` Georg Bauhaus @ 2008-01-04 14:17 ` Dmitry A. Kazakov 1 sibling, 0 replies; 14+ messages in thread From: Dmitry A. Kazakov @ 2008-01-04 14:17 UTC (permalink / raw) On Fri, 04 Jan 2008 14:08:52 +0100, Philippe Tarroux wrote: > Dmitry A. Kazakov a �crit : >> The function A_Data returns Data. It is a primitive operation of Data and >> thus covariant in the result. So when you derive anything from Data, you >> have to override it in order to provide a correct implementation that would >> return the derived type rather than the base. >> > Ok. But does it mean that only the constructor is a primitive operation > of the data type, not the print procedure? In this case why Print > doesn't need to be redefined? Right, the reason why Print need not to be overridden is that it has Data passed in the in-mode. So the caller has Data already constructed elsewhere. For the same reason a procedure with an in-out-mode parameter can be safely inherited too. Considering strictly out-mode parameters, it could be otherwise, in general case. But in Ada tagged types have to be constrained and constructed even when they are outs. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2008-01-04 15:38 UTC | newest] Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2008-01-03 15:20 tagged type as generic parameter Philippe Tarroux 2008-01-03 15:51 ` Dmitry A. Kazakov 2008-01-03 16:22 ` Adam Beneschan 2008-01-03 16:58 ` Dmitry A. Kazakov 2008-01-03 17:47 ` Jean-Pierre Rosen 2008-01-03 18:13 ` Pascal Obry 2008-01-03 19:20 ` Dmitry A. Kazakov 2008-01-03 21:37 ` Jeffrey R. Carter 2008-01-04 13:08 ` Philippe Tarroux 2008-01-04 15:03 ` Jean-Pierre Rosen 2008-01-04 13:08 ` Philippe Tarroux 2008-01-04 13:22 ` Georg Bauhaus 2008-01-04 15:38 ` Philippe Tarroux 2008-01-04 14:17 ` Dmitry A. Kazakov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox