* Quick question regarding limited type return syntax @ 2014-07-30 23:51 NiGHTS 2014-07-31 0:02 ` Adam Beneschan 2014-07-31 0:48 ` Shark8 0 siblings, 2 replies; 40+ messages in thread From: NiGHTS @ 2014-07-30 23:51 UTC (permalink / raw) I am designing a package which features a "Create" function that returns a newly instantiated "Object" which is a discriminated limited type. The code compiles and operates correctly but gives me a warning that "New_Object" is not used. See below (ellipses represent omitted code): ----- package Test is type Object (Parameters : access String) is tagged limited private; function Create (...) return Object; ... private type Object (Parameters : access String) is tagged limited record Database : PQ.Database (Parameters); ... end record; ... end Test; package body Test is function Create(...) return Object is ... begin return New_Object : Object (Connection_String'Access) do null; end return; end; ... end Test; ----- To remove this warning I've tried this: return Object (Connection_String'Access) do null; end return; and it gives an error about expecting a ';'. I've also tried this: return Object (Connection_String'Access); Compiler tells me "argument of conversion cannot be access". I have tried other syntax variants but all produce errors. My goal here is to avoid using "new" which is why I am trying to return the instance in this way. How can I rewrite this code so that I won't get any errors or warnings? ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-07-30 23:51 Quick question regarding limited type return syntax NiGHTS @ 2014-07-31 0:02 ` Adam Beneschan 2014-07-31 0:56 ` NiGHTS 2014-07-31 0:48 ` Shark8 1 sibling, 1 reply; 40+ messages in thread From: Adam Beneschan @ 2014-07-31 0:02 UTC (permalink / raw) On Wednesday, July 30, 2014 4:51:10 PM UTC-7, NiGHTS wrote: > I am designing a package which features a "Create" function that returns a newly instantiated "Object" which is a discriminated limited type. The code compiles and operates correctly but gives me a warning that "New_Object" is not used. See below (ellipses represent omitted code): > package Test is > type Object (Parameters : access String) is tagged limited private; > function Create (...) return Object; > ... > private > type Object (Parameters : access String) is tagged limited > record > Database : PQ.Database (Parameters); > ... > end record; > ... > end Test; > > package body Test is > function Create(...) return Object is > ... > begin > return New_Object : Object (Connection_String'Access) do > null; > end return; > end; > ... > end Test; > To remove this warning I've tried this: > > return Object (Connection_String'Access) do null; end return; > > and it gives an error about expecting a ';'. I've also tried this: > > > > return Object (Connection_String'Access); > > Compiler tells me "argument of conversion cannot be access". > > I have tried other syntax variants but all produce errors. My goal here is to avoid using "new" which is why I am trying to return the instance in this way. > > How can I rewrite this code so that I won't get any errors or warnings? What is a PQ.Database? I've tried this with various dummy types for the Database, and when I get a warning it's that the object is "read but never assigned". Is that the warning you're getting? That's different from a warning that says it's never used. It appears to me that if this field were assigned in New_Object, or if Database had an initial value in the record or if all components of Database had initial values, you wouldn't get the warning. -- Adam ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-07-31 0:02 ` Adam Beneschan @ 2014-07-31 0:56 ` NiGHTS 0 siblings, 0 replies; 40+ messages in thread From: NiGHTS @ 2014-07-31 0:56 UTC (permalink / raw) On Wednesday, July 30, 2014 8:02:59 PM UTC-4, Adam Beneschan wrote: > > What is a PQ.Database? > The complete name is GNATCOLL.SQL.Postgres.Gnade.Database. Its from the GNATColl library. https://github.com/ThomasLocke/GNATColl/blob/master/src/postgres/with_postgres/gnatcoll-sql-postgres-gnade.ads > > > I've tried this with various dummy types for the Database, and when I get a warning it's that the object is "read but never assigned". Is that the warning you're getting? That's different from a warning that says it's never used. > I'm sorry about that. You are right. That is the warning I am getting. > > It appears to me that if this field were assigned in New_Object, or if Database had an initial value in the record or if all components of Database had initial values, you wouldn't get the warning. > > The initial value is given during the return. It won't let me give it an initial value at the record definition (unless I am doing it wrong). Can you give me an example? ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-07-30 23:51 Quick question regarding limited type return syntax NiGHTS 2014-07-31 0:02 ` Adam Beneschan @ 2014-07-31 0:48 ` Shark8 2014-07-31 1:00 ` NiGHTS 1 sibling, 1 reply; 40+ messages in thread From: Shark8 @ 2014-07-31 0:48 UTC (permalink / raw) On 30-Jul-14 17:51, NiGHTS wrote: > return Object (Connection_String'Access) do null; end return; That should be return Object'(Connection_String'Access); the extended-return is the form return object:type [:= value] do sequence_of_statements end return; as you can see there's no 'do' there -- which is what the compiler was complaining about: there was no ';' between the value and "do". > return Object (Connection_String'Access); The reason this is failing is because it's reading the parens as conversion, not qualification -- for qualification you need a "'"; personally I'm a fan of using named parameters when using qualification and generating objects. return Object'(Parameters => Connection_String'Access, others => <>); ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-07-31 0:48 ` Shark8 @ 2014-07-31 1:00 ` NiGHTS 2014-07-31 1:29 ` Adam Beneschan 0 siblings, 1 reply; 40+ messages in thread From: NiGHTS @ 2014-07-31 1:00 UTC (permalink / raw) On Wednesday, July 30, 2014 8:48:34 PM UTC-4, Shark8 wrote: > On 30-Jul-14 17:51, NiGHTS wrote: > > > return Object (Connection_String'Access) do null; end return; > > > > That should be > > return Object'(Connection_String'Access); > > the extended-return is the form > > return object:type [:= value] do > > sequence_of_statements > > end return; > > > > as you can see there's no 'do' there -- which is what the compiler was > > complaining about: there was no ';' between the value and "do". > > > > > return Object (Connection_String'Access); > > > > The reason this is failing is because it's reading the parens as > > conversion, not qualification -- for qualification you need a "'"; > > personally I'm a fan of using named parameters when using qualification > > and generating objects. > > > > return Object'(Parameters => Connection_String'Access, others => <>); This was another syntax I had tried. Here is the error I am getting with your syntax: Expected type "Object" defined at (...) Found type access to subtype of "Standard.String" at line (...) Just to be clear this is my modification: package body Test is function Create(...) return Object is ... begin return Object'(Connection_String'Access); end; ... end Test; ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-07-31 1:00 ` NiGHTS @ 2014-07-31 1:29 ` Adam Beneschan 2014-07-31 1:38 ` NiGHTS 2014-08-01 2:12 ` Randy Brukardt 0 siblings, 2 replies; 40+ messages in thread From: Adam Beneschan @ 2014-07-31 1:29 UTC (permalink / raw) On Wednesday, July 30, 2014 6:00:43 PM UTC-7, NiGHTS wrote: > On Wednesday, July 30, 2014 8:48:34 PM UTC-4, Shark8 wrote: > > > On 30-Jul-14 17:51, NiGHTS wrote: > > > > return Object (Connection_String'Access) do null; end return; > package body Test is > function Create(...) return Object is > ... > begin > return Object'(Connection_String'Access); > end; > ... > end Test; What you need to do is return an aggregate. And to return an aggregate, you need to specify both fields--the Parameters discriminant and the Database. This syntax: Object'(Connection_String'Access) is just wrong. It tells the compiler that the value is Connection_String'Access, and asks the compiler to treat it as an Object. It can't do that, because Object isn't an access type. (This sort of syntax can be useful in overloading cases, when the compiler can't determine the correct access type without help.) If you said Object'(Parameters => Connection_String'Access) you'd get an error that Database is missing. So you need Object'(Parameters => Connection_String'Access, Database => <>) or just (Parameters => Connection_String'Access, Database => <>) or (Parameters => Connection_String'Access, others => <>) (It's OK for a function that returns a limited type to return an aggregate like this.) The effect is that subcomponents of Database that have default initial values will be initialized, and subcomponents that don't have default initial values will be initialized to garbage (except where the language says otherwise). That's really the same as your original example was trying to do. I guess that explicitly putting "others => <>" in an aggregate is enough to convince GNAT not to think you were accidentally leaving something initialized to garbage. -- Adam ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-07-31 1:29 ` Adam Beneschan @ 2014-07-31 1:38 ` NiGHTS 2014-07-31 4:01 ` Shark8 2014-08-01 2:12 ` Randy Brukardt 1 sibling, 1 reply; 40+ messages in thread From: NiGHTS @ 2014-07-31 1:38 UTC (permalink / raw) On Wednesday, July 30, 2014 9:29:10 PM UTC-4, Adam Beneschan wrote: > On Wednesday, July 30, 2014 6:00:43 PM UTC-7, NiGHTS wrote: > > > On Wednesday, July 30, 2014 8:48:34 PM UTC-4, Shark8 wrote: > > > > > > > On 30-Jul-14 17:51, NiGHTS wrote: > > > > > > > > return Object (Connection_String'Access) do null; end return; > > > > > package body Test is > > > function Create(...) return Object is > > > ... > > > begin > > > return Object'(Connection_String'Access); > > > end; > > > ... > > > end Test; > > > > What you need to do is return an aggregate. And to return an aggregate, you need to specify both fields--the Parameters discriminant and the Database. This syntax: > > > > Object'(Connection_String'Access) > > > > is just wrong. It tells the compiler that the value is Connection_String'Access, and asks the compiler to treat it as an Object. It can't do that, because Object isn't an access type. (This sort of syntax can be useful in overloading cases, when the compiler can't determine the correct access type without help.) > > > > If you said > > > > Object'(Parameters => Connection_String'Access) > > > > you'd get an error that Database is missing. So you need > > > > Object'(Parameters => Connection_String'Access, Database => <>) > > > > or just > > > > (Parameters => Connection_String'Access, Database => <>) > > > > or > > > > (Parameters => Connection_String'Access, others => <>) > > > > (It's OK for a function that returns a limited type to return an aggregate like this.) > > > > The effect is that subcomponents of Database that have default initial values will be initialized, and subcomponents that don't have default initial values will be initialized to garbage (except where the language says otherwise). That's really the same as your original example was trying to do. I guess that explicitly putting "others => <>" in an aggregate is enough to convince GNAT not to think you were accidentally leaving something initialized to garbage. > > > > -- Adam You're a good man Adam. Thank you for your very clear explanation. This worked for me and I'm very pleased by how logical this ended up being. And thank you as well Shark8 for your help. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-07-31 1:38 ` NiGHTS @ 2014-07-31 4:01 ` Shark8 0 siblings, 0 replies; 40+ messages in thread From: Shark8 @ 2014-07-31 4:01 UTC (permalink / raw) On 30-Jul-14 19:38, NiGHTS wrote: > And thank you as well Shark8 for your help. > Quite welcome. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-07-31 1:29 ` Adam Beneschan 2014-07-31 1:38 ` NiGHTS @ 2014-08-01 2:12 ` Randy Brukardt 2014-08-01 3:40 ` Shark8 2014-08-01 7:57 ` J-P. Rosen 1 sibling, 2 replies; 40+ messages in thread From: Randy Brukardt @ 2014-08-01 2:12 UTC (permalink / raw) "Adam Beneschan" <adambeneschan@gmail.com> wrote in message news:bf9193d6-e1a8-4df3-8e36-b07a2b07655e@googlegroups.com... ... >The effect is that subcomponents of Database that have default initial >values >will be initialized, and subcomponents that don't have default initial >values >will be initialized to garbage (except where the language says otherwise). >That's really the same as your original example was trying to do. I guess >that explicitly putting "others => <>" in an aggregate is enough to >convince GNAT not to think you were accidentally leaving something >initialized to garbage. I'd hope so: the syntax you gave says that you explicitly wanted something initialized to garbage. :-) [OK, explicitly default-initialized, whatever that does.] It's not a compiler's job to second-guess explicit instructions, programmers would get really annoyed if it did (and have a hard time getting anything done). It's annoying that we couldn't get this "explicit default-initialization" syntax more widely used. I prefer to ensure that everything is properly initialized, but sometimes the default value is good enough. It would be nice to be able to specify that: Obj : My_Type := <>; or maybe Obj : My_Type := (<>); so that I could verify that every object is either initialized or explicitly left default initialized. Right now, I use a comment: Obj : My_Type; -- Default initialize is OK here, because ... but it's hard for a tool to tell that everything is as it should be. (We tried to allow "(<>)" for private types for Ada 2005, but ran into a number of problems that eventually led us to give up. Too bad, I don't think they were insurmountable, but we were running short on time.) Randy. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-01 2:12 ` Randy Brukardt @ 2014-08-01 3:40 ` Shark8 2014-08-01 7:57 ` J-P. Rosen 1 sibling, 0 replies; 40+ messages in thread From: Shark8 @ 2014-08-01 3:40 UTC (permalink / raw) On 31-Jul-14 20:12, Randy Brukardt wrote: > (We tried to allow "(<>)" for private types for Ada 2005, but ran into a > number of problems that eventually led us to give up. Too bad, I don't think > they were insurmountable, but we were running short on time.) That's unfortunate. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-01 2:12 ` Randy Brukardt 2014-08-01 3:40 ` Shark8 @ 2014-08-01 7:57 ` J-P. Rosen 2014-08-01 19:23 ` Randy Brukardt 1 sibling, 1 reply; 40+ messages in thread From: J-P. Rosen @ 2014-08-01 7:57 UTC (permalink / raw) Le 01/08/2014 04:12, Randy Brukardt a écrit : > t's annoying that we couldn't get this "explicit default-initialization" > syntax more widely used. I prefer to ensure that everything is properly > initialized, but sometimes the default value is good enough. It would be > nice to be able to specify that: > > Obj : My_Type := <>; > or maybe > Obj : My_Type := (<>); > > so that I could verify that every object is either initialized or explicitly > left default initialized. One of my clients has a rule that every user-defined type must provide an associated constant for the default value (and of course, AdaControl can enforce that rule). Then it is enough to say that every variable must be initialized. Seems close enough to what you want... -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-01 7:57 ` J-P. Rosen @ 2014-08-01 19:23 ` Randy Brukardt 2014-08-01 19:37 ` J-P. Rosen 2014-08-01 20:53 ` Shark8 0 siblings, 2 replies; 40+ messages in thread From: Randy Brukardt @ 2014-08-01 19:23 UTC (permalink / raw) [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain, Size: 1176 bytes --] "J-P. Rosen" <rosen@adalog.fr> wrote in message news:lrfh8k$rpi$1@dont-email.me... > Le 01/08/2014 04:12, Randy Brukardt a écrit : >> t's annoying that we couldn't get this "explicit default-initialization" >> syntax more widely used. I prefer to ensure that everything is properly >> initialized, but sometimes the default value is good enough. It would be >> nice to be able to specify that: >> >> Obj : My_Type := <>; >> or maybe >> Obj : My_Type := (<>); >> >> so that I could verify that every object is either initialized or >> explicitly >> left default initialized. > > One of my clients has a rule that every user-defined type must provide > an associated constant for the default value (and of course, AdaControl > can enforce that rule). Then it is enough to say that every variable > must be initialized. > > Seems close enough to what you want... Not quite, since Default_Frobnitz : constant Frobnitz_Type; is illegal. You could write: Junk_Frobnitz : Frobnitz_Type; -- To get this default-initialized. Default_Frobnitz : constant Frobnitz_Type := Junk_Frobnitz; but that's awful. Randy. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-01 19:23 ` Randy Brukardt @ 2014-08-01 19:37 ` J-P. Rosen 2014-08-01 20:53 ` Shark8 1 sibling, 0 replies; 40+ messages in thread From: J-P. Rosen @ 2014-08-01 19:37 UTC (permalink / raw) Le 01/08/2014 21:23, Randy Brukardt a écrit : >> One of my clients has a rule that every user-defined type must provide >> > an associated constant for the default value (and of course, AdaControl >> > can enforce that rule). Then it is enough to say that every variable >> > must be initialized. >> > >> > Seems close enough to what you want... > Not quite, since > > Default_Frobnitz : constant Frobnitz_Type; > > is illegal. No, of course the constant has an explicitely stated value. -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-01 19:23 ` Randy Brukardt 2014-08-01 19:37 ` J-P. Rosen @ 2014-08-01 20:53 ` Shark8 2014-08-02 7:11 ` Niklas Holsti 2014-08-02 8:02 ` Jacob Sparre Andersen 1 sibling, 2 replies; 40+ messages in thread From: Shark8 @ 2014-08-01 20:53 UTC (permalink / raw) ...Too bad there's not a Default_Value sort of aspect/attribute. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-01 20:53 ` Shark8 @ 2014-08-02 7:11 ` Niklas Holsti 2014-08-02 7:34 ` Dmitry A. Kazakov 2014-08-02 8:02 ` Jacob Sparre Andersen 1 sibling, 1 reply; 40+ messages in thread From: Niklas Holsti @ 2014-08-02 7:11 UTC (permalink / raw) On 14-08-01 10:57 , J-P. Rosen wrote: > Le 01/08/2014 04:12, Randy Brukardt a écrit : >> It's annoying that we couldn't get this "explicit default- >> initialization" syntax more widely used. I prefer to ensure that >> everything is properly initialized, but sometimes the default >> value is good enough. It would be nice to be able to specify that: >> >> Obj : My_Type := <>; >> or maybe >> Obj : My_Type := (<>); >> >> so that I could verify that every object is either initialized >> or explicitly left default initialized. > > One of my clients has a rule that every user-defined type must > provide an associated constant for the default value (and of > course, AdaControl can enforce that rule). Then it is enough > to say that every variable must be initialized. > > Seems close enough to what you want... On 14-08-01 23:53 , Shark8 wrote: > ...Too bad there's not a Default_Value sort of aspect/attribute. Do you mean that Default_Value would be an aspect of a type, and would define the default initialization value of objects of that type? More elegantly IMO, the language could allow a default initialization expression to be assigned in the type or subtype declaration: type My_Type is <type definition> := <expression>; The elaboration of the type declaration would evalate the expression into a value, and then any declaration of an object of this type would use that value as the initialization expression, unless the object declaration itself provides an initialization expression. J-P's client's rule could then be reformulated as a rule that every type (and subtype) declaration must have a default-initialization expression. This suggestion seems so trivial that it has probably been made before, and rejected for some reason. Perhaps using ":=" to "assign a value to a type" is too strange. Randy's suggestion for an explicit indication that an object is default-initialized is an orthogonal isssue. IMO the risk of using uninitialized variables, and the resulting non-deterministic bugs, is one of the major remaining holes in the safety of Ada. On the other hand, explicit initialization of all variables (buffer arrays in particular) is often far too costly in real-time applications. The above suggestions of explicit default initialization expressions would not reduce the cost, of course. At present, the only remedy that does not impose run-time costs is to use provers to show that the uninitialized variables (for example, uninitialized array elements) are never read. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-02 7:11 ` Niklas Holsti @ 2014-08-02 7:34 ` Dmitry A. Kazakov 2014-08-02 13:20 ` Robert A Duff 0 siblings, 1 reply; 40+ messages in thread From: Dmitry A. Kazakov @ 2014-08-02 7:34 UTC (permalink / raw) On Sat, 02 Aug 2014 10:11:59 +0300, Niklas Holsti wrote: > More elegantly IMO, the language could allow a default initialization > expression to be assigned in the type or subtype declaration: > > type My_Type is <type definition> := <expression>; This suggests assigning something to the type. (The only way to have default initialization is by having a default constructor. Which is just same.) BTW, type Integer is range ... := 0; subtype Positive is Integer range 1..Integer'Last; X : Positive; -- Oops! [...] > Randy's suggestion for an explicit indication that an object is > default-initialized is an orthogonal isssue. Yes, and it would have sense if implicitly uninitialized objects were illegal. Unfortunately they are not. > IMO the risk of using uninitialized variables, and the resulting > non-deterministic bugs, is one of the major remaining holes in the > safety of Ada. All initialization/finalization issues are. E.g. parent's Initialize not called. Finalization deadlock with task components. Dispatching calls through class-wide access discriminants upon initialization/finalization. The holes are as big as the hull... -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-02 7:34 ` Dmitry A. Kazakov @ 2014-08-02 13:20 ` Robert A Duff 2014-08-02 13:44 ` Dmitry A. Kazakov 0 siblings, 1 reply; 40+ messages in thread From: Robert A Duff @ 2014-08-02 13:20 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >...Dispatching calls > through class-wide access discriminants upon initialization/finalization. Can you please give an example of what you mean? - Bob ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-02 13:20 ` Robert A Duff @ 2014-08-02 13:44 ` Dmitry A. Kazakov 2014-08-02 14:34 ` Robert A Duff 0 siblings, 1 reply; 40+ messages in thread From: Dmitry A. Kazakov @ 2014-08-02 13:44 UTC (permalink / raw) On Sat, 02 Aug 2014 09:20:45 -0400, Robert A Duff wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >>...Dispatching calls >> through class-wide access discriminants upon initialization/finalization. > > Can you please give an example of what you mean? Components not discriminants. I had Rosen's trick in mind: type T is ... Self : not null access T := T'Unchecked_Access; -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-02 13:44 ` Dmitry A. Kazakov @ 2014-08-02 14:34 ` Robert A Duff 2014-08-02 16:56 ` Dmitry A. Kazakov 0 siblings, 1 reply; 40+ messages in thread From: Robert A Duff @ 2014-08-02 14:34 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > On Sat, 02 Aug 2014 09:20:45 -0400, Robert A Duff wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >> >>>...Dispatching calls >>> through class-wide access discriminants upon initialization/finalization. >> >> Can you please give an example of what you mean? > > Components not discriminants. I had Rosen's trick in mind: > > type T is ... > Self : not null access T := T'Unchecked_Access; Sorry, I still don't get it. I don't see any class-wide types or dispatching calls there. Also, it's illegal as written (the Rosen trick is only allowed for limited types.) Perhaps a complete compilable example would help illustrate the language anomaly you are talking about. The Rosen trick allows you to obtain a variable view of a constant, but that has nothing to do with initialization/finalization, so I assume that's not what you meant. - Bob ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-02 14:34 ` Robert A Duff @ 2014-08-02 16:56 ` Dmitry A. Kazakov 2014-08-02 20:35 ` Niklas Holsti 2014-08-03 16:35 ` Robert A Duff 0 siblings, 2 replies; 40+ messages in thread From: Dmitry A. Kazakov @ 2014-08-02 16:56 UTC (permalink / raw) On Sat, 02 Aug 2014 10:34:53 -0400, Robert A Duff wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >> On Sat, 02 Aug 2014 09:20:45 -0400, Robert A Duff wrote: >> >>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >>> >>>>...Dispatching calls >>>> through class-wide access discriminants upon initialization/finalization. >>> >>> Can you please give an example of what you mean? >> >> Components not discriminants. I had Rosen's trick in mind: >> >> type T is ... >> Self : not null access T := T'Unchecked_Access; > > Sorry, I still don't get it. I don't see any class-wide types or > dispatching calls there. Also, it's illegal as written (the Rosen trick > is only allowed for limited types.) Perhaps a complete compilable > example would help illustrate the language anomaly you are talking > about. with Ada.Finalization; with Ada.Text_IO; procedure Test is package P is type T is new Ada.Finalization.Limited_Controlled with record Self : not null access T'Class := T'Unchecked_Access; end record; overriding procedure Initialize (X : in out T); procedure Foo (X : in out T) is null; end P; package body P is procedure Initialize (X : in out T) is begin X.Self.Foo; end Initialize; end P; package Q is use P; type S is new T with record I : Integer; end record; overriding procedure Initialize (X : in out S); overriding procedure Foo (X : in out S); end Q; package body Q is procedure Initialize (X : in out S) is begin T (X).Initialize; X.I := 1; end Initialize; procedure Foo (X : in out S) is begin X.I := X.I + 1; end Foo; end Q; Y : Q.S; begin Ada.Text_IO.Put_Line (Integer'Image (Y.I)); end Test; -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-02 16:56 ` Dmitry A. Kazakov @ 2014-08-02 20:35 ` Niklas Holsti 2014-08-03 7:30 ` Dmitry A. Kazakov 2014-08-03 16:35 ` Robert A Duff 1 sibling, 1 reply; 40+ messages in thread From: Niklas Holsti @ 2014-08-02 20:35 UTC (permalink / raw) On 14-08-02 19:56 , Dmitry A. Kazakov wrote: > On Sat, 02 Aug 2014 10:34:53 -0400, Robert A Duff wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >> >>> On Sat, 02 Aug 2014 09:20:45 -0400, Robert A Duff wrote: >>> >>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >>>> >>>>> ...Dispatching calls >>>>> through class-wide access discriminants upon initialization/finalization. >>>> >>>> Can you please give an example of what you mean? >>> >>> Components not discriminants. I had Rosen's trick in mind: >>> >>> type T is ... >>> Self : not null access T := T'Unchecked_Access; >> >> Sorry, I still don't get it. I don't see any class-wide types or >> dispatching calls there. Also, it's illegal as written (the Rosen trick >> is only allowed for limited types.) Perhaps a complete compilable >> example would help illustrate the language anomaly you are talking >> about. > > with Ada.Finalization; > with Ada.Text_IO; > procedure Test is > package P is > type T is new Ada.Finalization.Limited_Controlled with record > Self : not null access T'Class := T'Unchecked_Access; > end record; > overriding procedure Initialize (X : in out T); > procedure Foo (X : in out T) is null; > end P; > > package body P is > procedure Initialize (X : in out T) is > begin > X.Self.Foo; > end Initialize; > end P; > > package Q is > use P; > type S is new T with record > I : Integer; > end record; > overriding procedure Initialize (X : in out S); > overriding procedure Foo (X : in out S); > end Q; > > package body Q is > procedure Initialize (X : in out S) is > begin > T (X).Initialize; > X.I := 1; > end Initialize; > procedure Foo (X : in out S) is > begin > X.I := X.I + 1; > end Foo; > end Q; > > Y : Q.S; > begin > Ada.Text_IO.Put_Line (Integer'Image (Y.I)); > end Test; (Dmitry, I find it quite annoying that you just dump this code on us without bothering to explain why you think it shows some problem in Ada.) The code indeed accesses an uninitialized datum: when Y is initialized, Initialize (S) calls Initialize (T), which makes a dispatching call to Foo (S), which accesses the component S.I, which is not yet initialized. The flow of control in the example is a bit sneaky, but the self-referring component T.Self is in no way essential to the sneakiness; the same could be achieved by simply making a redispatching call to Foo in Initialize(T). There are many other ways to create even sneakier flow of control with even more obscure opportunities for accessing uninitialized data. Perhaps you have some personal design and coding rules which would prevent access to uninitialized data except for the kind of code shown in the example? That is, perhaps the ability to write such code in Ada breaks the safety of your design and coding rules? Perhaps the rule is that the Initialize operation of a derived type should first call Initialize on the parent type, and only then initialize the components added in the derivation (the extension components)? That is not a bad rule, but combining it with (re-)dispatching calls to operations overridden in the derived type obviously invites errors of the kind shown in the example. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-02 20:35 ` Niklas Holsti @ 2014-08-03 7:30 ` Dmitry A. Kazakov 2014-08-04 9:24 ` Niklas Holsti 0 siblings, 1 reply; 40+ messages in thread From: Dmitry A. Kazakov @ 2014-08-03 7:30 UTC (permalink / raw) On Sat, 02 Aug 2014 23:35:34 +0300, Niklas Holsti wrote: > On 14-08-02 19:56 , Dmitry A. Kazakov wrote: >> On Sat, 02 Aug 2014 10:34:53 -0400, Robert A Duff wrote: >> >>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >>> >>>> On Sat, 02 Aug 2014 09:20:45 -0400, Robert A Duff wrote: >>>> >>>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >>>>> >>>>>> ...Dispatching calls >>>>>> through class-wide access discriminants upon initialization/finalization. >>>>> >>>>> Can you please give an example of what you mean? >>>> >>>> Components not discriminants. I had Rosen's trick in mind: >>>> >>>> type T is ... >>>> Self : not null access T := T'Unchecked_Access; >>> >>> Sorry, I still don't get it. I don't see any class-wide types or >>> dispatching calls there. Also, it's illegal as written (the Rosen trick >>> is only allowed for limited types.) Perhaps a complete compilable >>> example would help illustrate the language anomaly you are talking >>> about. >> >> with Ada.Finalization; >> with Ada.Text_IO; >> procedure Test is >> package P is >> type T is new Ada.Finalization.Limited_Controlled with record >> Self : not null access T'Class := T'Unchecked_Access; >> end record; >> overriding procedure Initialize (X : in out T); >> procedure Foo (X : in out T) is null; >> end P; >> >> package body P is >> procedure Initialize (X : in out T) is >> begin >> X.Self.Foo; >> end Initialize; >> end P; >> >> package Q is >> use P; >> type S is new T with record >> I : Integer; >> end record; >> overriding procedure Initialize (X : in out S); >> overriding procedure Foo (X : in out S); >> end Q; >> >> package body Q is >> procedure Initialize (X : in out S) is >> begin >> T (X).Initialize; >> X.I := 1; >> end Initialize; >> procedure Foo (X : in out S) is >> begin >> X.I := X.I + 1; >> end Foo; >> end Q; >> >> Y : Q.S; >> begin >> Ada.Text_IO.Put_Line (Integer'Image (Y.I)); >> end Test; > > (Dmitry, I find it quite annoying that you just dump this code on us > without bothering to explain why you think it shows some problem in Ada.) Sorry, but the problem was self-evident to me. Robert asked for a working example so I scraped together one without much thinking. > The code indeed accesses an uninitialized datum: when Y is initialized, > Initialize (S) calls Initialize (T), which makes a dispatching call to > Foo (S), which accesses the component S.I, which is not yet initialized. The code prematurely dispatches on an not yet initialized object. Again, it was evident that this would happen when having a class-wide accessible in Initialize when the parent's Initialize is to be called at the beginning of the derived type Initialize. > The flow of control in the example is a bit sneaky, but the > self-referring component T.Self is in no way essential to the > sneakiness; the same could be achieved by simply making a redispatching > call to Foo in Initialize(T). Yes, but as you probably remember, re-dispatching is already damned as inconsistent regardless initialization. > There are many other ways to create even sneakier flow of control with > even more obscure opportunities for accessing uninitialized data. There is no safe way to do initialization in Ada because it is not properly typed. You should not be able to dispatch until the class-wide instance is fully initialized, but you can because types are broken. > Perhaps you have some personal design and coding rules which would > prevent access to uninitialized data except for the kind of code shown > in the example? That is, perhaps the ability to write such code in Ada > breaks the safety of your design and coding rules? Perhaps the rule is > that the Initialize operation of a derived type should first call > Initialize on the parent type, and only then initialize the components > added in the derivation (the extension components)? That is not a bad > rule, but combining it with (re-)dispatching calls to operations > overridden in the derived type obviously invites errors of the kind > shown in the example. The problem is with the semantics of Initialize, with its types. 1. IF Initialize does the specific type THEN it cannot dispatch AND it must be through before any derived type's Initialize. 2. IF Initialize does class-wide type THEN it can dispatch AND must be called after derived type's initialization. It is sometimes one, sometimes another, sometimes both. It is a mess. Note that there is a similar problem with constraints (with type invariants, more generally): type Not_Working is Ref : not null access Something; end record; This does not work for the same reason. There is no constructor which would see Not_Working.Ref not yet initialized (without the constraint, when type invariant not in place). Compare this with a class-wide access component to itself. There is no constructor of the type itself which would see it not initialized. In both cases there can be a second level initialization where the offending component is fully operational. But it cannot be both. Both means types broken. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-03 7:30 ` Dmitry A. Kazakov @ 2014-08-04 9:24 ` Niklas Holsti 2014-08-04 10:42 ` G.B. ` (2 more replies) 0 siblings, 3 replies; 40+ messages in thread From: Niklas Holsti @ 2014-08-04 9:24 UTC (permalink / raw) On 14-08-03 10:30 , Dmitry A. Kazakov wrote: > On Sat, 02 Aug 2014 23:35:34 +0300, Niklas Holsti wrote: > >> On 14-08-02 19:56 , Dmitry A. Kazakov wrote: >>> On Sat, 02 Aug 2014 10:34:53 -0400, Robert A Duff wrote: >>> >>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >>>> >>>>> On Sat, 02 Aug 2014 09:20:45 -0400, Robert A Duff wrote: >>>>> >>>>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >>>>>> >>>>>>> ...Dispatching calls >>>>>>> through class-wide access discriminants upon initialization/finalization. >>>>>> >>>>>> Can you please give an example of what you mean? >>>>> >>>>> Components not discriminants. I had Rosen's trick in mind: >>>>> >>>>> type T is ... >>>>> Self : not null access T := T'Unchecked_Access; >>>> >>>> Sorry, I still don't get it. I don't see any class-wide types or >>>> dispatching calls there. Also, it's illegal as written (the Rosen trick >>>> is only allowed for limited types.) Perhaps a complete compilable >>>> example would help illustrate the language anomaly you are talking >>>> about. >>> >>> with Ada.Finalization; >>> with Ada.Text_IO; >>> procedure Test is >>> package P is >>> type T is new Ada.Finalization.Limited_Controlled with record >>> Self : not null access T'Class := T'Unchecked_Access; >>> end record; >>> overriding procedure Initialize (X : in out T); >>> procedure Foo (X : in out T) is null; >>> end P; >>> >>> package body P is >>> procedure Initialize (X : in out T) is >>> begin >>> X.Self.Foo; >>> end Initialize; >>> end P; >>> >>> package Q is >>> use P; >>> type S is new T with record >>> I : Integer; >>> end record; >>> overriding procedure Initialize (X : in out S); >>> overriding procedure Foo (X : in out S); >>> end Q; >>> >>> package body Q is >>> procedure Initialize (X : in out S) is >>> begin >>> T (X).Initialize; >>> X.I := 1; >>> end Initialize; >>> procedure Foo (X : in out S) is >>> begin >>> X.I := X.I + 1; >>> end Foo; >>> end Q; >>> >>> Y : Q.S; >>> begin >>> Ada.Text_IO.Put_Line (Integer'Image (Y.I)); >>> end Test; >> >> (Dmitry, I find it quite annoying that you just dump this code on us >> without bothering to explain why you think it shows some problem in Ada.) > > Sorry, but the problem was self-evident to me. Robert asked for a working > example so I scraped together one without much thinking. Apology accepted, no hard feelings. >> The code indeed accesses an uninitialized datum: when Y is initialized, >> Initialize (S) calls Initialize (T), which makes a dispatching call to >> Foo (S), which accesses the component S.I, which is not yet initialized. > > The code prematurely dispatches on an not yet initialized object. Again, it > was evident that this would happen when having a class-wide accessible in > Initialize when the parent's Initialize is to be called at the beginning of > the derived type Initialize. I see what you mean, and I remember that you have often criticized Ada for lacking "proper constructors". Controlled types in Ada provide hooks (Initialize/Finalize/Adjust) that can be used as constructors and destructors, but it is up to the programmer to design the logic, for example to decide which object components are initialized in Initialize, and when. In this area, Ada is perhaps more liberal than languages which have a stricter object-oriented view. I don't agree that dispatching on a controlled object should be illegal until the Initialize operation on that object has been completed. I believe that such dispatching may be quite useful in some designs, just as re-dispatching is useful in some designs - IMO. Moreover, I think this question of constructor/destructor control flow is separate from the general question of preventing access to uninitialized data. As I understand it, even in the languages which do have specific constructor/destructor facilities, there is no requirement or check that a constructor must initialize all the components of the object (but I'm not sure how Java works in this case). > There is no safe way to do initialization in Ada because it is not properly > typed. You should not be able to dispatch until the class-wide instance is > fully initialized, I don't agree on that. > but you can because types are broken. If dispatching hurts you, don't do it :-) (I'll think more about the rest of the points you made, and perhaps reply later.) -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-04 9:24 ` Niklas Holsti @ 2014-08-04 10:42 ` G.B. 2014-08-04 11:39 ` Peter Chapin 2014-08-04 11:36 ` Peter Chapin 2014-08-04 12:43 ` Dmitry A. Kazakov 2 siblings, 1 reply; 40+ messages in thread From: G.B. @ 2014-08-04 10:42 UTC (permalink / raw) On 04.08.14 11:24, Niklas Holsti wrote: > As I understand it, even in the languages which do > have specific constructor/destructor facilities, there is no requirement > or check that a constructor must initialize all the components of the > object (but I'm not sure how Java works in this case). Java lets you write Ada: class T { public T() { this.foo(); } protected void foo() {} } class S extends T { public Integer I; public S() { // calls super // I not initialized (and not allocated) this.I = 1; } @Override protected void foo() { this.I += 1; } } class Dispatching { public static void main(String[] args) { S Y = new S(); } } This program will stop after throwing a NullPointerException. If S.I is made an int, the default value is 0, and the above program is considered bad style(*). C++, I think, lets "this" stand for the type at the current "level" during construction, so there is no dispatching to lower levels IIUC; however, Stroustrup mentions some pointer tricks that let the programmer circumvent the restriction. (*) http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-04 10:42 ` G.B. @ 2014-08-04 11:39 ` Peter Chapin 2014-08-04 17:49 ` Niklas Holsti 0 siblings, 1 reply; 40+ messages in thread From: Peter Chapin @ 2014-08-04 11:39 UTC (permalink / raw) On 2014-08-04 06:42, G.B. wrote: > C++, I think, lets "this" stand for the type at the current "level" > during construction, so there is no dispatching to lower levels IIUC; > however, Stroustrup mentions some pointer tricks that let the > programmer circumvent the restriction. It's true that in C++ dynamic dispatch is "turned off" during the execution of a constructor (and destructor). This is precisely to prevent the use of an uninitialized object when a base subobject is being constructed (or destroyed). It's a feature! It seems to me that circumventing it would be like circumventing the type system. You might be able to do it but... it would be a big warning flag that something is wrong. Peter ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-04 11:39 ` Peter Chapin @ 2014-08-04 17:49 ` Niklas Holsti 0 siblings, 0 replies; 40+ messages in thread From: Niklas Holsti @ 2014-08-04 17:49 UTC (permalink / raw) On 14-08-04 14:39 , Peter Chapin wrote: > On 2014-08-04 06:42, G.B. wrote: > >> C++, I think, lets "this" stand for the type at the current "level" >> during construction, so there is no dispatching to lower levels IIUC; >> however, Stroustrup mentions some pointer tricks that let the >> programmer circumvent the restriction. > > It's true that in C++ dynamic dispatch is "turned off" during the > execution of a constructor (and destructor). This is precisely to > prevent the use of an uninitialized object when a base subobject is > being constructed (or destroyed). It's a feature! It seems to me that > circumventing it would be like circumventing the type system. It is a circumvention of the C++ type (or class) system because it has been made so intentionally, by the logical meaning given to constructors in the language. > You might > be able to do it but... it would be a big warning flag that something is > wrong. "Wrong" from the point of view of the C++ object philosophy, yes, but IMO not necessarily wrong for the Ada object philosophy, where the Initialize primitive does not have such a strong predefined meaning (which is just what Dmitry complains about). -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-04 9:24 ` Niklas Holsti 2014-08-04 10:42 ` G.B. @ 2014-08-04 11:36 ` Peter Chapin 2014-08-04 12:43 ` Dmitry A. Kazakov 2 siblings, 0 replies; 40+ messages in thread From: Peter Chapin @ 2014-08-04 11:36 UTC (permalink / raw) On 2014-08-04 05:24, Niklas Holsti wrote: > Moreover, I think this question of constructor/destructor control flow > is separate from the general question of preventing access to > uninitialized data. As I understand it, even in the languages which do > have specific constructor/destructor facilities, there is no requirement > or check that a constructor must initialize all the components of the > object. With C++ the language does not require this check but there are tools that do it. The tools are nice because if you add a member they will remind you to take care of it in your constructors. The tools are not perfect. I suspect full handling of this issue may be undecidable because the constructor can call arbitrary recursive methods as part of it's work. So tracking precisely which members get initialized would be quite difficult in the general case. Peter ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-04 9:24 ` Niklas Holsti 2014-08-04 10:42 ` G.B. 2014-08-04 11:36 ` Peter Chapin @ 2014-08-04 12:43 ` Dmitry A. Kazakov 2014-08-04 16:19 ` G.B. 2014-08-04 19:37 ` Niklas Holsti 2 siblings, 2 replies; 40+ messages in thread From: Dmitry A. Kazakov @ 2014-08-04 12:43 UTC (permalink / raw) On Mon, 04 Aug 2014 12:24:19 +0300, Niklas Holsti wrote: > Controlled types in Ada provide hooks (Initialize/Finalize/Adjust) that > can be used as constructors and destructors, Not really. The problem is that they hook too late to be specific type constructor and too early for a specific type destructor. This is why you can dispatch from there. The problem arise when you attempt both: use Initialize as if it were a specific constructor hook and dispatch from it. > I don't agree that dispatching on a controlled object should be illegal > until the Initialize operation on that object has been completed. Then you cannot call Initialize a constructor's hook. These two are mutually exclusive. You can dispatch not before all specific descendants are constructed and T'Class itself. To make it clearer consider what would be the post-condition of Initialize: type T is ...; type S is new T ...; Initialize (X : in out T) ensure T'Operational (X) [*] or, maybe S'Operational (X) T'Class'Operational (X) S'Class'Operational (X) Now, the precondition of a dispatching call on T'Class is obviously: require T'Class'Is_Operational (X) Of course: T'Class'Operational (X) => T'Operational (X) T'Class'Operational (X) => S'Operational (X) From this you can formally analyse if initialization is correct. > I believe that such dispatching may be quite useful in some designs, Yes it is. This is why there must be a hook at the end of construction of T'Class. The earliest point you can dispatch if when T'Class'Operational turns true. > just as re-dispatching is useful in some designs - IMO. No. This is a totally different case. > Moreover, I think this question of constructor/destructor control flow > is separate from the general question of preventing access to > uninitialized data. ? Initialization = construction. I don't see how are they different. ----------------- * T'Operational (X) is true when the object X can operate as an instance of T. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-04 12:43 ` Dmitry A. Kazakov @ 2014-08-04 16:19 ` G.B. 2014-08-04 16:38 ` Dmitry A. Kazakov 2014-08-04 19:37 ` Niklas Holsti 1 sibling, 1 reply; 40+ messages in thread From: G.B. @ 2014-08-04 16:19 UTC (permalink / raw) On 04.08.14 14:43, Dmitry A. Kazakov wrote: > To make it clearer consider what would be the post-condition of Initialize: > > type T is ...; > type S is new T ...; > > Initialize (X : in out T) > ensure > T'Operational (X) > > [*] or, maybe > > S'Operational (X) > T'Class'Operational (X) > S'Class'Operational (X) > > Now, the precondition of a dispatching call on T'Class is obviously: > > require > T'Class'Is_Operational (X) The model is circular, I think, in that you stipulate that 'Operational must be a "premiss" for a dispatching call, using "obvious" as the sole reason. But while I think that everything else is a hack, some specific dispatching scenario need not even require the allocation of any of the derived type's components, for when no callee needs them, they don't matter, and still the whole object is 'Operational (in this sense). Not that I can now think of a case that is both useful and cannot be "architected" in some other, perhaps better way. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-04 16:19 ` G.B. @ 2014-08-04 16:38 ` Dmitry A. Kazakov 2014-08-04 16:51 ` G.B. 0 siblings, 1 reply; 40+ messages in thread From: Dmitry A. Kazakov @ 2014-08-04 16:38 UTC (permalink / raw) On Mon, 04 Aug 2014 18:19:16 +0200, G.B. wrote: > On 04.08.14 14:43, Dmitry A. Kazakov wrote: > >> To make it clearer consider what would be the post-condition of Initialize: >> >> type T is ...; >> type S is new T ...; >> >> Initialize (X : in out T) >> ensure >> T'Operational (X) >> >> [*] or, maybe >> >> S'Operational (X) >> T'Class'Operational (X) >> S'Class'Operational (X) >> >> Now, the precondition of a dispatching call on T'Class is obviously: >> >> require >> T'Class'Is_Operational (X) > > The model is circular, I think, in that you stipulate > that 'Operational must be a "premiss" for a dispatching call, > using "obvious" as the sole reason. How isn't obvious and how is it circular? A dispatching = primitive operation is defined on the whole class. That is the definition of. The argument of a dispatching call is of the type T'Class. This is also per definition. How can you call an operation of the type on an object of this type when the former is not yet operational? > But while I think that > everything else is a hack, some specific dispatching scenario > need not even require the allocation of any of the derived > type's components, for when no callee needs them, they don't > matter, and still the whole object is 'Operational (in this > sense). Maybe, but this does not follow from the types at hand. If the language allowed partial classes you could be able to express something like T'Class \ S -- All types derived from T but S a dispatching call to anything but Foo of S might work. That would require definition of a primitive operation of a partial class. procedure Foo (X : in out T \ S); -- Whatever -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-04 16:38 ` Dmitry A. Kazakov @ 2014-08-04 16:51 ` G.B. 2014-08-04 17:23 ` Dmitry A. Kazakov 0 siblings, 1 reply; 40+ messages in thread From: G.B. @ 2014-08-04 16:51 UTC (permalink / raw) On 04.08.14 18:38, Dmitry A. Kazakov wrote: > How can you call an operation of the type on an object of this type when > the former is not yet operational? In a way that is somewhat like you say, namely on a partial object when it is needed only partially: T.comp_1: allocated and possibly initialized S.comp_2: not even allocated overriding procedure Foo (X : in out S) is begin null; end Foo; may "validly" become: alloc comp_1 jump s.foo s.foo: ret Lousy, but it may "work", even when, without optimization, some "non-existing junk" is copied for X (if it's not by ref). Not that I want that! Just imagine the outcome should the arbitrary location happen to be volatile… ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-04 16:51 ` G.B. @ 2014-08-04 17:23 ` Dmitry A. Kazakov 0 siblings, 0 replies; 40+ messages in thread From: Dmitry A. Kazakov @ 2014-08-04 17:23 UTC (permalink / raw) On Mon, 04 Aug 2014 18:51:47 +0200, G.B. wrote: > On 04.08.14 18:38, Dmitry A. Kazakov wrote: >> How can you call an operation of the type on an object of this type when >> the former is not yet operational? > > In a way that is somewhat like you say, namely on a partial > object when it is needed only partially: As I said you must define "partially." This must be in type terms. So long you don't do that, it is an untyped mess. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-04 12:43 ` Dmitry A. Kazakov 2014-08-04 16:19 ` G.B. @ 2014-08-04 19:37 ` Niklas Holsti 2014-08-05 8:30 ` Dmitry A. Kazakov 1 sibling, 1 reply; 40+ messages in thread From: Niklas Holsti @ 2014-08-04 19:37 UTC (permalink / raw) On 14-08-04 15:43 , Dmitry A. Kazakov wrote: > On Mon, 04 Aug 2014 12:24:19 +0300, Niklas Holsti wrote: > >> Controlled types in Ada provide hooks (Initialize/Finalize/Adjust) that >> can be used as constructors and destructors, > > Not really. Ok, I should have said "for similar purposes as constructors and destructors". > The problem is that they hook too late to be specific type > constructor and too early for a specific type destructor. This is why you > can dispatch from there. The problem arise when you attempt both: use > Initialize as if it were a specific constructor hook and dispatch from it. You have a certain concept of what a "constructor" should do, and should not do; the latter includes dispatching. Ada allows dispatching from Initialize, but you can disallow it by a personal design and coding rule. >> I don't agree that dispatching on a controlled object should be illegal >> until the Initialize operation on that object has been completed. > > Then you cannot call Initialize a constructor's hook. Depends on the meaning you assign to "constructor". In Ada, the object is created and default-initialized (or initialized by component-specific Initialize calls) before Initialize is called on it. In this sense, construction in Ada is automatic, and Initialize is only a "post-constructor" hook. > To make it clearer consider what would be the post-condition of Initialize: > > type T is ...; > type S is new T ...; > > Initialize (X : in out T) > ensure > T'Operational (X) > > [*] or, maybe > > S'Operational (X) > T'Class'Operational (X) > S'Class'Operational (X) You have invented a boolean predicate "Operational". In practice, objects do not have only two states: "not operational" and "operational"; they have several states, and "initialization" is often a multi-step process which takes the object through a sequence of logical states, from its default-initialized state to whatever level of initialization is desired at this stage. For a well-worn example, a File object is usually born in a "closed" state, and is then "operational" only in a limited sense; later, opening the File makes it more "operational". Some steps in the initialization process, while described in the semantics of the parent type (the 'Class), may need assistance that is specific to a derived type, and therefore dispatching from Initialize may be useful. For example, the 'Class semantics may include registration of all objects in some registry, but this registry may need some object-specific data that depends on the particular type of the object and is provided by a dispatching operation. > Now, the precondition of a dispatching call on T'Class is obviously: > > require > T'Class'Is_Operational (X) > > Of course: > > T'Class'Operational (X) => T'Operational (X) > T'Class'Operational (X) => S'Operational (X) > > From this you can formally analyse if initialization is correct. Only in your limited, two-state formalization, which IMO is not realistic. >> Moreover, I think this question of constructor/destructor control flow >> is separate from the general question of preventing access to >> uninitialized data. > > ? Initialization = construction. I don't see how are they different. The point is that for some data structures, it is not desirable to initialize (= store data in) all allocated storage locations when the data structure is created. The reason can be that initialization is too costly, and the initialization values are never used; or the reason can be that the initialization could only assign dummy values, and therefore would only ensure that later errors have a deterministic effect, but could not ensure that no dummy initial values are used by mistake as non-dummy values. The canonical example is a large array that will be used as a stack, or in which data blocks will be allocated and deallocated in some other controlled way. Thus, the array is created (i.e. allocated or constructed) but usually it still contains uninitialized and therefore unpredictable data (at least in traditional processors and operating systems -- some new or security-conscious systems have memory allocators which do initialize all allocated memory areas, albeit with dummy values such as zeros). Such data structures usually have special components which "indicate" which parts of the data structure are initialized and usable, and which parts are not. For example, a stack pointer can perform this role for an array that implements a stack. But current programming languages, including Ada, do not provide any general support for this logical connection between "indicators" and initialized/uninitialized data; the connection must in each case be specifically formalized and then used to prove that any data that is read has first been initialized (with real values). My aim was to complain about this lack of language support for such "indicators" and other features that help to prove that a program never uses uninitialized variables (nor dummy values). I don't know what form this support should take, however. As a partial analogy, discriminant checks for variant records in Ada ensure that non-existent components are not accessed, but do not ensure that the accessed components are initialized with useful values. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-04 19:37 ` Niklas Holsti @ 2014-08-05 8:30 ` Dmitry A. Kazakov 2014-08-05 19:24 ` Randy Brukardt 0 siblings, 1 reply; 40+ messages in thread From: Dmitry A. Kazakov @ 2014-08-05 8:30 UTC (permalink / raw) On Mon, 04 Aug 2014 22:37:27 +0300, Niklas Holsti wrote: > On 14-08-04 15:43 , Dmitry A. Kazakov wrote: >> On Mon, 04 Aug 2014 12:24:19 +0300, Niklas Holsti wrote: >> >>> Controlled types in Ada provide hooks (Initialize/Finalize/Adjust) that >>> can be used as constructors and destructors, >> >> Not really. > > Ok, I should have said "for similar purposes as constructors and > destructors". > >> The problem is that they hook too late to be specific type >> constructor and too early for a specific type destructor. This is why you >> can dispatch from there. The problem arise when you attempt both: use >> Initialize as if it were a specific constructor hook and dispatch from it. > > You have a certain concept of what a "constructor" should do, and should > not do; the latter includes dispatching. Ada allows dispatching from > Initialize, but you can disallow it by a personal design and coding rule. No. I use the standard meaning of the constructor. Constructor is a thing that makes a type instance from the chunk of raw memory. Then I consider types T, S, T'Class, S'Class and conclude whether the corresponding constructors could dispatch from within. This has nothing to do with specifically Ada or with my personal choices. >>> I don't agree that dispatching on a controlled object should be illegal >>> until the Initialize operation on that object has been completed. >> >> Then you cannot call Initialize a constructor's hook. > > Depends on the meaning you assign to "constructor". See above. > In Ada, the object is created and default-initialized (or initialized by > component-specific Initialize calls) before Initialize is called on it. The object is allocated and initialized by whatever means. The second part is called constructor. Initialize is a part of the constructor (a hook). > In this sense, construction in Ada is automatic, and Initialize is only > a "post-constructor" hook. Yes. It is always so, because per definition a constrictor cannot be a typed subprogram since it *changes* the object's type from nothing to a distinct type. We can only hook it, as Initialize does. C++ "constructors' are just hooks as well. >> To make it clearer consider what would be the post-condition of Initialize: >> >> type T is ...; >> type S is new T ...; >> >> Initialize (X : in out T) >> ensure >> T'Operational (X) >> >> [*] or, maybe >> >> S'Operational (X) >> T'Class'Operational (X) >> S'Class'Operational (X) > > You have invented a boolean predicate "Operational". In practice, > objects do not have only two states: "not operational" and > "operational"; they have several states, and "initialization" is often a > multi-step process which takes the object through a sequence of logical > states, from its default-initialized state to whatever level of > initialization is desired at this stage. You could refine that in the terms of language types, I gave an example when answering to Georg. But presently Ada has it in the all-or-nothing form. > For a well-worn example, a File object is usually born in a "closed" > state, and is then "operational" only in a limited sense; later, opening > the File makes it more "operational". No. File_Type from Ada.Text_IO is operational in all its states = you are allowed to use any operations of Ada.Text_IO on a closed file. No problem. You could attempt to introduce a file type that were operational only when open. In that case you would have to ensure it open before you leave the constructor. You could not close it before running the destructor. Formally speaking it is whether Is_Open is a part of the type invariant or not. > Some steps in the initialization process, while described in the > semantics of the parent type (the 'Class), may need assistance that is > specific to a derived type, and therefore dispatching from Initialize > may be useful. Nobody argues that dispatching from constructors were not useful. The point is - dispatching from the constructor of WHAT? You can dispatch only at the end of the constructor of T'Class. You cannot dispatch nowhere from the constructor of T. >> Now, the precondition of a dispatching call on T'Class is obviously: >> >> require >> T'Class'Is_Operational (X) >> >> Of course: >> >> T'Class'Operational (X) => T'Operational (X) >> T'Class'Operational (X) => S'Operational (X) >> >> From this you can formally analyse if initialization is correct. > > Only in your limited, two-state formalization, which IMO is not realistic. Show me tree-state, four-state formalization. My sole requirement is, don't break types, Ada is supposed to be a typed language. >>> Moreover, I think this question of constructor/destructor control flow >>> is separate from the general question of preventing access to >>> uninitialized data. >> >> ? Initialization = construction. I don't see how are they different. > > The point is that for some data structures, it is not desirable to > initialize (= store data in) all allocated storage locations when the > data structure is created. They are still initialized with the garbage. No problem. You think of initialization as of spending some CPU cycles. It is not. The only purpose of initialization is to bring the type invariant up and thus to make the object operational. The invariant can be just True. > My aim was to complain about this lack of language support for such > "indicators" and other features that help to prove that a program never > uses uninitialized variables (nor dummy values). This is an unrelated issue. An "uninitialized" object like: X : Integer; is still fully constructed, operational and initialized, but not in the sense of initialization you used = an explicit specification that the new object must be in the state so and so. > I don't know what form > this support should take, however. 1. An ability do disallow default constructors, as it was done for indefinite types: X : String; -- Illegal (no constructor) 2. Integration of SPARK. When you about prove X having certain value, the prover will not be able to do that if the thing was never assigned. 3. Proper construction model. You must be able to write type ... is record P : not null access Something; and then the compiler must require you to provide a constructor and add the post-condition on P to it. 4. Proper construction model. X : T := Y; must call to a constructor (hook) with the parameter Y. 5. Proper construction model. X : T (Y, Z); must call to a constructor with the parameters (Y, Z). 6. Proper construction model. X : T := (Y, Z); must call to a constructor with the parameters (Y, Z), *not* with an aggregate. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-05 8:30 ` Dmitry A. Kazakov @ 2014-08-05 19:24 ` Randy Brukardt 0 siblings, 0 replies; 40+ messages in thread From: Randy Brukardt @ 2014-08-05 19:24 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:a9ius0ptyh6x.x33ggbcx3wo3$.dlg@40tude.net... ... > Yes. It is always so, because per definition a constrictor cannot be a > typed subprogram ... This typo gave me a good laugh! In future examples, I'll have to remember to name constructor functions "Boa" Then I'll have a "Boa constructor". :-) Randy. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-02 16:56 ` Dmitry A. Kazakov 2014-08-02 20:35 ` Niklas Holsti @ 2014-08-03 16:35 ` Robert A Duff 1 sibling, 0 replies; 40+ messages in thread From: Robert A Duff @ 2014-08-03 16:35 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > procedure Initialize (X : in out T) is > begin > X.Self.Foo; > end Initialize; Thanks. Yes, dispatching on a not-fully-constructed object is problematic. - Bob ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-01 20:53 ` Shark8 2014-08-02 7:11 ` Niklas Holsti @ 2014-08-02 8:02 ` Jacob Sparre Andersen 2014-08-02 19:20 ` Shark8 1 sibling, 1 reply; 40+ messages in thread From: Jacob Sparre Andersen @ 2014-08-02 8:02 UTC (permalink / raw) Shark8 <OneWingedShark@gmail.com> writes: > ...Too bad there's not a Default_Value sort of aspect/attribute. LRM 3.5(56.3/3) Enjoy, Jacob -- "I'm going as a barrel of toxic waste!" ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Quick question regarding limited type return syntax 2014-08-02 8:02 ` Jacob Sparre Andersen @ 2014-08-02 19:20 ` Shark8 2014-08-03 16:07 ` Default values (Was: Quick question regarding limited type return syntax) Jacob Sparre Andersen 0 siblings, 1 reply; 40+ messages in thread From: Shark8 @ 2014-08-02 19:20 UTC (permalink / raw) On 02-Aug-14 02:02, Jacob Sparre Andersen wrote: > Shark8 <OneWingedShark@gmail.com> writes: > >> ...Too bad there's not a Default_Value sort of aspect/attribute. > > LRM 3.5(56.3/3) > > Enjoy, > > Jacob It's only for scalar types though. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Default values (Was: Quick question regarding limited type return syntax) 2014-08-02 19:20 ` Shark8 @ 2014-08-03 16:07 ` Jacob Sparre Andersen 2014-08-04 21:29 ` Randy Brukardt 0 siblings, 1 reply; 40+ messages in thread From: Jacob Sparre Andersen @ 2014-08-03 16:07 UTC (permalink / raw) Shark8 wrote: > On 02-Aug-14 02:02, Jacob Sparre Andersen wrote: >> Shark8 <OneWingedShark@gmail.com> writes: >> LRM 3.5(56.3/3) > > It's only for scalar types though. That's because the one for arrays is named Default_Component_Value - and record components can have their default values declared without aspects. Enjoy, Jacob -- "You've got to build bypasses!" ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: Default values (Was: Quick question regarding limited type return syntax) 2014-08-03 16:07 ` Default values (Was: Quick question regarding limited type return syntax) Jacob Sparre Andersen @ 2014-08-04 21:29 ` Randy Brukardt 0 siblings, 0 replies; 40+ messages in thread From: Randy Brukardt @ 2014-08-04 21:29 UTC (permalink / raw) "Jacob Sparre Andersen" <jacob@jacob-sparre.dk> wrote in message news:87sild4kvs.fsf_-_@adaheads.sparre-andersen.dk... > Shark8 wrote: >> On 02-Aug-14 02:02, Jacob Sparre Andersen wrote: >>> Shark8 <OneWingedShark@gmail.com> writes: > >>> LRM 3.5(56.3/3) >> >> It's only for scalar types though. > > That's because the one for arrays is named Default_Component_Value - and > record components can have their default values declared without > aspects. And access types are already default initialized to null, protected type components are like record components, and there's nothing visible in a task that needs initialization. It's not a perfect solution in that you can't change the default initialization of an access type nor of an array type with non-scalar components, but it ensures that it is possible to provide (or have one by definition) a real default initialization for every type. Randy. ^ permalink raw reply [flat|nested] 40+ messages in thread
end of thread, other threads:[~2014-08-05 19:24 UTC | newest] Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2014-07-30 23:51 Quick question regarding limited type return syntax NiGHTS 2014-07-31 0:02 ` Adam Beneschan 2014-07-31 0:56 ` NiGHTS 2014-07-31 0:48 ` Shark8 2014-07-31 1:00 ` NiGHTS 2014-07-31 1:29 ` Adam Beneschan 2014-07-31 1:38 ` NiGHTS 2014-07-31 4:01 ` Shark8 2014-08-01 2:12 ` Randy Brukardt 2014-08-01 3:40 ` Shark8 2014-08-01 7:57 ` J-P. Rosen 2014-08-01 19:23 ` Randy Brukardt 2014-08-01 19:37 ` J-P. Rosen 2014-08-01 20:53 ` Shark8 2014-08-02 7:11 ` Niklas Holsti 2014-08-02 7:34 ` Dmitry A. Kazakov 2014-08-02 13:20 ` Robert A Duff 2014-08-02 13:44 ` Dmitry A. Kazakov 2014-08-02 14:34 ` Robert A Duff 2014-08-02 16:56 ` Dmitry A. Kazakov 2014-08-02 20:35 ` Niklas Holsti 2014-08-03 7:30 ` Dmitry A. Kazakov 2014-08-04 9:24 ` Niklas Holsti 2014-08-04 10:42 ` G.B. 2014-08-04 11:39 ` Peter Chapin 2014-08-04 17:49 ` Niklas Holsti 2014-08-04 11:36 ` Peter Chapin 2014-08-04 12:43 ` Dmitry A. Kazakov 2014-08-04 16:19 ` G.B. 2014-08-04 16:38 ` Dmitry A. Kazakov 2014-08-04 16:51 ` G.B. 2014-08-04 17:23 ` Dmitry A. Kazakov 2014-08-04 19:37 ` Niklas Holsti 2014-08-05 8:30 ` Dmitry A. Kazakov 2014-08-05 19:24 ` Randy Brukardt 2014-08-03 16:35 ` Robert A Duff 2014-08-02 8:02 ` Jacob Sparre Andersen 2014-08-02 19:20 ` Shark8 2014-08-03 16:07 ` Default values (Was: Quick question regarding limited type return syntax) Jacob Sparre Andersen 2014-08-04 21:29 ` Randy Brukardt
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox