* Task components, the rationale @ 2011-07-13 18:52 Dmitry A. Kazakov 2011-07-13 20:58 ` Maciej Sobczak 0 siblings, 1 reply; 6+ messages in thread From: Dmitry A. Kazakov @ 2011-07-13 18:52 UTC (permalink / raw) OK, to avoid false impression that Ada was carelessly designed, it must be said that there was a valid reason why task components are broken this way. That is to prevent a much worse disaster when so-called Rosen's trick is used. Consider the pattern discussed earlier (the Rosen's trick): type T; task type Worker (Self : not null access T'Class); type T is new Ada.Finalization.Limited_Controlled with record My_Worker : Worker (T'Access); end record; overriding procedure Initialize (Object : in out T); procedure Foo (Object : in out T) is abstract; -- A primitive operation Now, if My_Worker started before completion of Initialize then this body task body Worker is begin Self.Foo; -- Boom! could call Foo of T or any of its derived type *before* Initialize, i.e. before the object's construction is done! That would be a much worse problem. There is no simple solution for this. To start with tasks must be inheritable from and their bodies must be primitive or class-wide operations, because aggregation (composition) + Rosen's trick is necessarily broken. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Task components, the rationale 2011-07-13 18:52 Task components, the rationale Dmitry A. Kazakov @ 2011-07-13 20:58 ` Maciej Sobczak 2011-07-14 8:52 ` Georg Bauhaus 2011-07-14 9:23 ` Dmitry A. Kazakov 0 siblings, 2 replies; 6+ messages in thread From: Maciej Sobczak @ 2011-07-13 20:58 UTC (permalink / raw) On Jul 13, 8:52 pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> wrote: > Now, if My_Worker started before completion of Initialize then this body > > task body Worker is > begin > Self.Foo; -- Boom! > > could call Foo of T or any of its derived type *before* Initialize, i.e. > before the object's construction is done! That would be a much worse > problem. I don't even think you need to introduce tasks to show the problem - what if the component is of another controlled type? Then you have two nested calls to distinct Initialize operations - the first one for the component (where you have the discriminant access value to play with) and the second one for the whole, which is too late: with Ada.Finalization; with Ada.Text_IO; procedure Test is type Outer; type Inner (Shell : access Outer) is new Ada.Finalization.Limited_Controlled with null record; overriding procedure Initialize (Self : in out Inner); type Outer is new Ada.Finalization.Limited_Controlled with record I : Inner (Outer'Access); Some_Value : Integer; end record; overriding procedure Initialize (Self : in out Outer); procedure Initialize (Self : in out Inner) is begin Ada.Text_IO.Put_Line ("initializing inner, Self.Shell.Some_Value =" & Integer'Image (Self.Shell.all.Some_Value)); end Initialize; procedure Initialize (Self : in out Outer) is begin Self.Some_Value := 123; Ada.Text_IO.Put_Line ("initialized outer, Some_Value =" & Integer'Image (Self.Some_Value)); end Initialize; X : Outer; begin null; end Test; $ gnatmake test ... $ ./test initializing inner, Self.Shell.Some_Value = 0 initialized outer, Some_Value = 123 $ We are messing with the state that does not yet exist. Oops. > There is no simple solution for this. You have to just, you know, simply, introduce constructors to the language. This is my pet feature for Ada 2020. :-) > To start with tasks must be > inheritable from and their bodies must be primitive or class-wide > operations, because aggregation (composition) + Rosen's trick is > necessarily broken. It's not about tasks, it's about access discriminants to outer records - they introduce circular references (outer has inner, inner knows outer) and as such are evil. -- Maciej Sobczak * http://www.msobczak.com * http://www.inspirel.com ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Task components, the rationale 2011-07-13 20:58 ` Maciej Sobczak @ 2011-07-14 8:52 ` Georg Bauhaus 2011-07-14 18:15 ` Maciej Sobczak 2011-07-14 9:23 ` Dmitry A. Kazakov 1 sibling, 1 reply; 6+ messages in thread From: Georg Bauhaus @ 2011-07-14 8:52 UTC (permalink / raw) On 7/13/11 10:58 PM, Maciej Sobczak wrote: > On Jul 13, 8:52 pm, "Dmitry A. Kazakov"<mail...@dmitry-kazakov.de> >> There is no simple solution for this. > > You have to just, you know, simply, introduce constructors to the > language. This is my pet feature for Ada 2020. :-) Out of curiosity, would this be enough? How will it work? Assuming, naively, not knowing C++, that constructors of C++ could lead the way, I get #include <iostream> namespace { class Outer; class Inner { private: Outer* shell; public: Inner(Outer*); }; class Outer { private: Inner i; public: int some_value; Outer(); }; Inner::Inner(Outer* wrap) { this->shell = wrap; std::cout << "initializing inner, this->shell->some_value = " << this->shell->some_value << std::endl; } Outer::Outer() : i(this) { this->some_value = 123; std::cout << "initialized outer, this->some_value = " << this->some_value << std::endl; } } int main() { Outer x; return 0; } $ c++ news23.cpp $ ./a.out initializing inner, this->shell->some_value = 1606422610 initialized outer, this->some_value = 123 $ ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Task components, the rationale 2011-07-14 8:52 ` Georg Bauhaus @ 2011-07-14 18:15 ` Maciej Sobczak 2011-07-22 23:28 ` Randy Brukardt 0 siblings, 1 reply; 6+ messages in thread From: Maciej Sobczak @ 2011-07-14 18:15 UTC (permalink / raw) On Jul 14, 10:52 am, Georg Bauhaus <rm.dash-bauh...@futureapps.de> wrote: > > You have to just, you know, simply, introduce constructors to the > > language. This is my pet feature for Ada 2020. :-) > > Out of curiosity, would this be enough? It would not be sufficient, but it would be necessary. The point is, in order to solve these kind of puzzles you have to recognize initialization as a special operation (ie. stop pretending that it can be a regular primitive operation of a type) and use that notion to impose special rules. In the case of access discriminants the circular relationship is possible to discover statically. After all, the whole T'Access "expression" is special, and allowed only in this particular case. Once you statically know you have a problem, you can work from there - but no matter what kind of restrictions or provisions you impose in the constructor, you have to recognize that it is a special operation, not a regular primitive one. If you ask me from the top of my head how *exactly* this can be solved, I will not attempt to give a full solution (hey, the committee has a full decade for it ;-) ), but one of the possible ideas might involve adding a lifetime information to the access discriminant, just as it is done for tracking scopes of types and objects with anonymous access parameters today. That is, raise Program_Error when you discover that within the constructor of T its access discriminant (pointer to outer) is dereferenced while the outer was not yet initialized. Most cases (like the two examples we have shown) can be fully analyzed statically for this. > Assuming, naively, not knowing C++, that constructors of C++ > could lead the way, They will not lead the way in solving the problem of dangling pointers, because this is not the problem that C++ was designed to solve in general. But recognizing that the constructor is a special place is an important contribution. -- Maciej Sobczak * http://www.msobczak.com * http://www.inspirel.com ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Task components, the rationale 2011-07-14 18:15 ` Maciej Sobczak @ 2011-07-22 23:28 ` Randy Brukardt 0 siblings, 0 replies; 6+ messages in thread From: Randy Brukardt @ 2011-07-22 23:28 UTC (permalink / raw) "Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message news:a30f4a5d-baee-40b5-b30d-2a15042868e7@r9g2000yql.googlegroups.com... ... >If you ask me from the top of my head how *exactly* this can be >solved, I will not attempt to give a full solution (hey, the committee >has a full decade for it ;-) ), Well, actually, work on Ada 2020 would need to be finished by late 2018 in order to have a good chance of being standardized in 2020. Since it is mid-2011 now, I think that is more like 7 years than 10. ... > but one of the possible ideas might >involve adding a lifetime information to the access discriminant, just >as it is done for tracking scopes of types and objects with anonymous >access parameters today. That was suggested for Ada 2012 [by me and others], and it turns out that it cannot be done (at least with the sorts of lifetime indications that Ada has used to date). If it was mandated, it would necessarily make Ada implementations far more expensive than they currently are -- so I doubt very much that we'll see that. (Sorry, I don't remember which AI we were discussing at the time, so I can't give you a reference.) The static accessibility model for access discriminants is *very* problematical; it leads to distributed overhead for functions that might return something with a discriminant -- yet that still is considered preferable to any dynamic model. My preference is to not use them at all (not always possible, as shown by some of these examples). Randy. Randy. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Task components, the rationale 2011-07-13 20:58 ` Maciej Sobczak 2011-07-14 8:52 ` Georg Bauhaus @ 2011-07-14 9:23 ` Dmitry A. Kazakov 1 sibling, 0 replies; 6+ messages in thread From: Dmitry A. Kazakov @ 2011-07-14 9:23 UTC (permalink / raw) On Wed, 13 Jul 2011 13:58:36 -0700 (PDT), Maciej Sobczak wrote: > On Jul 13, 8:52�pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> > wrote: > >> Now, if My_Worker started before completion of Initialize then this body >> >> � �task body Worker is >> � �begin >> � � � �Self.Foo; -- Boom! >> >> could call Foo of T or any of its derived type *before* Initialize, i.e. >> before the object's construction is done! That would be a much worse >> problem. > > I don't even think you need to introduce tasks to show the problem - > what if the component is of another controlled type? Yes, but the hack was made specifically for tasks. If anybody wished to have safe construction/destruction in presence of components spoiled by the Rosen's trick, he would need to postpone parts of constructors/destructors to arrange them in certain order. It guaranteed is impossible to do in certain cases. With task components that manifests itself as a deadlock. (I don't know if the problem is detectable through static analysis, but I doubt it is.) >> There is no simple solution for this. > > You have to just, you know, simply, introduce constructors to the > language. This is my pet feature for Ada 2020. :-) Well, constructors need to be properly crafted to handle this. Note that the problem is in inconsistencies at the typing level. Returning to the tasks, you have to properly attribute the task body. Is it a primitive operation? Is it class-wide? etc. Depending on that you should be able or not to dispatch from the body and that will determine the earliest stage of construction when the body is allowed to start and the latest point before it started. I think it would not be possible to do without class-wide constructors, e.g. ones constructing classes out of specific types. (This is a subproblem of a more general problem: dispatching upon construction/destruction.) >> To start with tasks must be >> inheritable from and their bodies must be primitive or class-wide >> operations, because aggregation (composition) + Rosen's trick is >> necessarily broken. > > It's not about tasks, it's about access discriminants to outer records > - they introduce circular references (outer has inner, inner knows > outer) and as such are evil. Yes. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2011-07-22 23:28 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2011-07-13 18:52 Task components, the rationale Dmitry A. Kazakov 2011-07-13 20:58 ` Maciej Sobczak 2011-07-14 8:52 ` Georg Bauhaus 2011-07-14 18:15 ` Maciej Sobczak 2011-07-22 23:28 ` Randy Brukardt 2011-07-14 9:23 ` 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