!standard E.2.2(6) 10-02-15 AI05-0206-1/01 !class binding interpretation 10-02-15 !status work item 10-02-15 !status received 10-01-15 !priority Low !difficulty Medium !qualifier Omission !subject Remote_Types packages should be able to depend on Preelaborated packages !summary A Remote_Types package can semantically depend on a Preelaborated package so long as that dependency is via private with clause. !question The restrictions for Remote_Types packages are intended to allow the visible part of the package to meet various requirements. The bodies of Remote_Types packages have weaker requirements; they can declare non-remote access types, for instance. It is annoying that such types cannot be imported into a Remote_Types package. For instance, the following is a useful organization, which is illegal in Ada today: package X is type T is null record; type T_Access is access all T; end X; private with Ada.Finalization; private with X; package RT is pragma Remote_Types; type W is private; private type W is new Ada.Finalization.Controlled with D : X.T_Access; end record; end RT; Should this be changed? (Yes.) !proposal (See wording.) !wording ** TBD ** !discussion The body of a Remote_Types unit can depend on preelaborated packages, but not "regular" packages (as a Remote_Types unit is considered preelaborated, so 10.2.1(11/1) applies). Extending such access to private parts seems reasonable, ans shouldn't be able to open up any new holes. Note that this change probably eliminates the need for A(4) (since all of the packages in question are already preelaborated); we should consider dropping that rule. As such, this is considered an update of AI05-0060-1, and is classified as a Binding Interpretation (as is AI05-0060-1). --!corrigendum A.4.4(3) !ACATS test Create an ACATS C-Test to test that the packages can be used as Remote_Types packages. !appendix From: Vadim Godunko Sent: Friday, January 15, 2010 2:21 PM It would be nice to relax categorization constraints for privately with-ed packages by Remote_Types package and allow to privately with non-Remote_Types package. For example, following code is not a valid Ada2005 code but represents useful pattern: package X is type T is null record; type T_Access is access all T; end X; private with Ada.Finalization; private with X; package RT is pragma Remote_Types; type W is private; private type W is new Ada.Finalization.Controlled with D : X.T_Access; end record; end RT; **************************************************************** From: Brad Moore Sent: Friday, January 15, 2010 7:37 PM One issue I see is that this could violate E.2.2 (5) that says a remote library unit shall be preelaborable. Allowing this as proposed could introduce all sorts of elaboration problems that would be difficult to sort out in a distributed system. To get around that, we could consider having the restriction that the package being withed in the specification of a Remote_Types library unit would have to have a pragma Preelaborate, (or a pragma Pure, Passive, or Remote_Types but those categorization types are already allowed). Then there is E.2.2 (7) that says that a Remote Types shall not contain the declaration of any variable within the visible part of the library unit. Since this privately withed package does not have any such restrictions, it may be possible to provide such a package with a visible variable that can affect the state of the component in the private part of the Remote_Types package. That is a problem because modifying the variable in one partition likely wont apply to other instances of the Remote_Type in other partitions. So my initial take on this, is that this likely isn't workable, or would impose too much of an implementation burden on the compiler writers, in my opinion. At least it is not clear to me how these issues would be circumvented. This appears to be a case of a low-hanging fruit as seen from a distance, until one gets closer, one realizes the tree it is hanging on is a mature redwood. In your example, one possibility would be to add a pragma Pure to package X, if package X satisfies the rules for a pure package. **************************************************************** From: Vadim Godunko Sent: Friday, January 15, 2010 9:56 PM > One issue I see is that this could violate E.2.2 (5) that says a > remote library unit shall be preelaborable. Allowing this as proposed > could introduce all sorts of elaboration problems that would be > difficult to sort out in a distributed system. To get around that, we > could consider having the restriction that the package being withed in > the specification of a Remote_Types library unit would have to have a > pragma Preelaborate, (or a pragma Pure, Passive, or Remote_Types but > those categorization types are already allowed). It is definitely reasonable to restrict privately with-ed units to be Preelaborate. > Then there is E.2.2 (7) that says that a Remote Types shall not > contain the declaration of any variable within the visible part of the > library unit. Since this privately withed package does not have any > such restrictions, it may be possible to provide such a package with a > visible variable that can affect the state of the component in the > private part of the Remote_Types package. That is a problem because > modifying the variable in one partition likely wont apply to other > instances of the Remote_Type in other partitions. It is expected behavior. > In your example, one possibility would be to add a pragma Pure to > package X, if package X satisfies the rules for a pure package. It is impossible to define named access type (without 'Storage_Size = 0) in the Pure unit. **************************************************************** From: Randy Brukardt Sent: Friday, January 15, 2010 10:17 PM ... > > Then there is E.2.2 (7) that says that a Remote Types shall not > > contain the declaration of any variable within the visible part of > > the library unit. Since this privately withed package does not have > > any such restrictions, it may be possible to provide such a package > > with a visible variable that can affect the state of the component > > in the private part of the Remote_Types package. That is a problem > > because modifying the variable in one partition likely wont apply to > > other instances of the Remote_Type in other partitions. > > > It is expected behavior. This sounds weird, to say the least. I thought the intent of the Distributed Systems annex was to define rules so that a distributed system has the same logical effect as the same code compiled as a single program (ignoring timing issues of course). You seem to be suggesting that the program could do something wildly different when distributed than if use as a single program. That doesn't seem right to me. I would expect that you'd need a Privately_Remoteable categorization in order to apply appropriate restrictions on such packages (it would be fairly similar to Preelaborable, but not necessarily exactly - the variable issue being one obvious concern). An alternative would be to require restrictions on in which partitions such packages can reside, but I'm not sure if that can be accomplished through the DS Annex's rules. > > In your example, one possibility would be to add a pragma Pure to > > package X, if package X satisfies the rules for a pure package. > > > It is impossible to define named access type (without 'Storage_Size = > 0) in the Pure unit. I have to wonder if putting heap-allocated objects into the private part of a Remote_Types package wouldn't make it hard/impossible to distribute? I haven't thought about this much, but it sounds like an expansion of the model that wouldn't necessarily work. **************************************************************** From: Brad Moore Sent: Saturday, January 16, 2010 2:38 PM > It is expected behavior. I would see this as a major problem that would need addressing. Currently in Ada, the programming interface for a Remote Access to Class Wide (RACW) type is cleanly defined and fully captured in the visible part of a Remote_Types package. If such a RACW type contains a component that can be affected by a visible variable in some far away package, then we are effectively sprinkling the interface to that type throughout the system. Furthermore, the "safety" of the component is compromised I think, because the exposed variable might be manipulated by other parts of the system that are unaware of the impact on distributed variables. Setting such a variable would probably only impact the RACW instances that designate objects in the same partition. For example, on partition may have an array of such RACW objects that were distributed from various partitions including the local one. Having a variable change cause some of these objects but not all of them change in "wildly" different ways, as Randy put it, seems like "unexpected" behaviour to me. I think though that Randy's idea of creating some sort of a Privately_Remoteable categorization would be a way to provide a potential solution. Such a categorization could also require that the library unit be preelaborable and not contain the declaration of any variable within the visible part of the library unit. I think we would also say that this categorization would also depend semantically only on declared pure, or other Privately_Remoteable library units. I think this could work. However, I am not sure that the ability of being able to privately with non-Remote types packages in a Remote_Types unit is worth adding the complexity of another categorization type to the language. I see that as the question that would need to be answered by the Ada community. There may be other alternatives to provide this feature, but at this point in time, I do not see any. I am not convinced this feature would be worthwhile, but I am somewhat on the borderline. As with other language feature proposals, it can be helpful to make the case for the feature if there are some good examples showing the need for the feature, particularly if there aren't reasonable workarounds. Can you provide a more concrete example? Is it not possible to modify your package X so that it is a Remote_Types package? Can the access type be moved to the private part, another package or removed altogether? Can package RT declare the access type in the private part instead, or use an anonymous access type for the component D? **************************************************************** From: Vadim Godunko Sent: Sunday, January 15, 2010 11:04 AM > Can you provide a more concrete example? Here is one of real example: http://adaforge.qtada.com/cgi-bin/tracker.fcgi/matreshka/browser/trunk/matreshka/source/league/league-strings.ads This package provides some form of unbounded string. Users visible type Universal_String in the package League.Strings is a wrapper around pointer to object where actual data is stored (its declaration see in the package Matreshka.Internals.Strings). "Wrapper" package hides from the end user all complexity of memory management, there internal type used by others units to avoid controlled type overhead. > Is it not possible to modify your package X so that it is a Remote_Types > package? It provides unnecessary inefficiency in the distributed version of the application. More than, types in this package is definitely local by its nature. > Can the access > type be moved to the private part, another package or removed > altogether? Can package RT declare the access type in the private part > instead, or use an anonymous access type for the component D? I suppose some times such tricks can improve situation, but in this concrete case it is impractical to declare internal package as Remote_Types and impossible to downgrade it to Pure. **************************************************************** From: Vadim Godunko Sent: Sunday, January 17, 2010 11:07 AM > I have to wonder if putting heap-allocated objects into the private > part of a Remote_Types package wouldn't make it hard/impossible to > distribute? I haven't thought about this much, but it sounds like an > expansion of the model that wouldn't necessarily work. It is usual practice, even in Ada standard - just take a look to implementation of Containers.* ;-) **************************************************************** From: Brad Moore Sent: Monday, January 18, 2010 10:41 AM > This package provides some form of unbounded string. Users visible > type Universal_String in the package League.Strings is a wrapper > around pointer to object where actual data is stored (its declaration > see in the package Matreshka.Internals.Strings). "Wrapper" package > hides from the end user all complexity of memory management, there > internal type used by others units to avoid controlled type overhead. OK, I am starting to see the usefulness of this feature. Also, a month ago you asked why Ada.Strings.Unbounded could not have the Remote_Types pragma. At the time the discussion was centred around the idea of eliminating the declaration for String_Access, since it was the reason why the pragma could not be added, especially since the access type was not referenced anywhere else in the visible part of the package. Removing the declaration would create a backwards incompatibility though. However if we had a "Privately_Remoteable" pragma, then we could leave the declaration in the package, yet still use the unbounded_string in the private part of other Remote_Types library units. That seems to be an attractive alternative to introducing a backwards incompatibility, although it would still mean that Unbounded Strings objects could not be distributed without being wrapped in some other Remote_Types object. In the case of your real example, my initial thought after a quick look at your code, is that modifying your package to not have visible access types would have a significant impact on the design of your package, which could have a "snowball" effect and affect other packages that with this package. I see that a Privately_Remoteable pragma would be helpful for you. A couple of other thoughts. I believe it is the case that such a pragma would only be needed for packages that contain visible access types that otherwise could have the Remote_Types pragma. Secondly, it is worth considering how this pragma would fit in with the Shared_Passive pragma. The categorization pragmas of Annex E fall into a hierarchy where each pragma can only depend semantically on library units with either the same pragma, or units that have pragmas higher in the hierarchy. Any new categorization pragma should ideally have this same property to be consistent. The question then becomes where in the hierarchy would such a pragma fit? Could such library units depend semantically on Shared_Passive units, or could Shared_Passive units depend semantically on these "Privately_Remoteable" units? If Shared_Passive units can with a "privately remoteable" unit, then privately remoteable units would have to satisfy the restrictions of a Shared_Passive unit. (Such as Access types cannot designate tasks or protected types with entries). On the other hand if "privately remoteable" units can with Shared_Passive units, then Shared_Passive units would not be able to use this feature. I tend to think that it would be better to say that "privately remoteable" units can with Shared_Passive units, because Shared_Passive units are less common, and mostly this feature would be useful for enabling units to have the Remote_Types pragma. Being able to use access types that designate tasks and protected types with entries also seems useful to me. It will be interesting to see what others think of this "privately remoteable" pragma idea. **************************************************************** From: Thomas Quinot Sent: Tuesday, January 19, 2010 4:25 AM > One issue I see is that this could violate E.2.2 (5) that says a > remote library unit shall be preelaborable. Allowing this as proposed > could introduce all sorts of elaboration problems that would be > difficult to sort out in a distributed system. To get around that, we > could consider having the restriction that the package being withed in > the specification of a Remote_Types library unit would have to have a > pragma Preelaborate, (or a pragma Pure, Passive, or Remote_Types but > those categorization types are already allowed). Yes. > Then there is E.2.2 (7) that says that a Remote Types shall not > contain the declaration of any variable within the visible part of the > library unit. Since this privately withed package does not have any > such restrictions, it may be possible to provide such a package with a > visible variable that can affect the state of the component in the > private part of the Remote_Types package. That is a problem because > modifying the variable in one partition likely wont apply to other > instances of the Remote_Type in other partitions. Not sure what scenario you have in mind. The same applies to a regular package with'd in the body of a remote types unit. Pretty much anything [preelaborable] is permitted in the private part of an RT unit, so it seems reasonable to also permit private with clauses, which won't make anything visible that doesn't satisfy the rules restricting the contents of the *visible* part of an RT unit. Note that a remote types unit is also allowed to have non-remote subprograms that could affect the value of any variable declared in the private part... > So my initial take on this, is that this likely isn't workable, or > would impose too much of an implementation burden on the compiler > writers, in my opinion. At least it is not clear to me how these > issues would be circumvented. Can you elaborate on what implementation difficulties you are thinking about? **************************************************************** From: Thomas Quinot Sent: Tuesday, January 19, 2010 4:29 AM > For example, on partition may have an array of such RACW objects that > were distributed from various partitions including the local one. > Having a variable change cause some of these objects but not all of > them change in "wildly" different ways, as Randy put it, seems like > "unexpected" behaviour to me. But this issue is already present in the language in any case, and not related at all to Vadim's proposal of allowing private with's of non-remote-types, preelaborated units. (The initial idea, as far as I know, being to allow passing unbounded strings in remote calls, not an unreasonable thing I'd say). > I think this could work. However, I am not sure that the ability of > being able to privately with non-Remote types packages in a > Remote_Types unit is worth adding the complexity of another > categorization type to the language. I agree, there's really no need for a new categorization here. **************************************************************** From: Randy Brukardt Sent: Tuesday, January 19, 2010 4:36 PM ... > > For example, on partition may have an array of such RACW objects > > that were distributed from various partitions including the local one. > > Having a variable change cause some of these objects but not all of > > them change in "wildly" different ways, as Randy put it, seems like > > "unexpected" behaviour to me. > > But this issue is already present in the language in any case, and not > related at all to Vadim's proposal of allowing private with's of > non-remote-types, preelaborated units. (The initial idea, as far as I > know, being to allow passing unbounded strings in remote calls, not an > unreasonable thing I'd say). It's not currently possible to write a type declaration in the private part of a remotes type package that depends on a variable declared in another package that is just preelaborable. This proposal would allow that. Such a variable could have different values in each partition (since it is not part of a shared package). That means that any type that depends on a different variable could have different constraints. Imagine a type with a component whose bounds are constrained by such a variable: the object would have different "shapes" in each partition. You are right that such a thing can happen in the language currently, but only in a single partition so there is no problem (There could be a problem for unrelated cooperating programs using streaming to communicate, but that is not a language issue). The partitioning rules are intended to prevent cases where a partitioned program would work differently than a program in a single partition, and this appears to be such a case. (An admittedly not very likely case.) If we're going to give up on the safety of Annex E in favor of expediency, then we should simply delete it from the language. It would have no remaining value (especially as only one vendor is supporting the annex; they might as well do as they please since anything using it isn't portable to another vendor's implementation anyway). **************************************************************** From: Brad Moore Sent: Wednesday, January 20, 2010 12:02 PM > Not sure what scenario you have in mind. The same applies to a regular > package with'd in the body of a remote types unit. Pretty much > anything [preelaborable] is permitted in the private part of an RT > unit, so it seems reasonable to also permit private with clauses, > which won't make anything visible that doesn't satisfy the rules > restricting the contents of the *visible* part of an RT unit. > > Note that a remote types unit is also allowed to have non-remote > subprograms that could affect the value of any variable declared in > the private part... Good points. I think I now agree with you that a new categorization pragma isn't needed and doesn't buy us much. It does seem desirable to be able to say that types declared in a remote types unit cannot be affected by visible variables in another package, but that really doesn't hold true now, since Shared_Passive units can declare such variables. > > So my initial take on this, is that this likely isn't workable, or > > would impose too much of an implementation burden on the compiler > > writers, in my opinion. At least it is not clear to me how these > > issues would be circumvented. > > Can you elaborate on what implementation difficulties you are thinking > about? I was thinking that if we want to enforce that visible variables cannot be declared in packages that are privately withed in Remote Types units, without a special pragma the compiler would not only have to enforce this property in the packages being privately withed, but also in any other semantic dependencies associated with the withed package. I think the presence of a special pragma would make this easier to do because the withed unit would not have compiled if it did not satisfy the rules of the pragma. The presence of the pragma in a privately withed unit would otherwise be good enough for the compiler to ensure the property holds true. I am uncertain whether there would really be implementation difficulties, or whether they would be significant. If we can say that it does not matter whether variables are declared in such privately withed units, then this is a moot point. > It's not currently possible to write a type declaration in the private > part of a remotes type package that depends on a variable declared in > another package that is just preelaborable. This proposal would allow > that. True, but is this a problem? > Such a variable could have different values in each partition (since > it is not part of a shared package). That means that any type that > depends on a different variable could have different constraints. > Imagine a type with a component whose bounds are constrained by such a > variable: the object would have different "shapes" in each partition. Even with a shared package this can lead to variables that have different shapes in each partition, (and even different shapes within the same partition). See below. > > You are right that such a thing can happen in the language currently, > but only in a single partition so there is no problem (There could be > a problem for unrelated cooperating programs using streaming to > communicate, but that is not a language issue). The partitioning rules > are intended to prevent cases where a partitioned program would work > differently than a program in a single partition, and this appears to > be such a case. (An admittedly not very likely case.) package B is pragma Shared_Passive; type Shapes is (Circle, Square, Triangle); Shape : Shapes := Square; end B; with B; package A is pragma Remote_Types; type Foo is tagged limited private; private type Foo is tagged limited record Shape : B.Shapes := B.Shape; end record; end A; with A; with B; procedure Main is Foo_1 : A.Foo; -- Is a square begin B.Shape := B.Triangle; declare Foo_2 : A.Foo; -- Is a triangle begin null; end; end Test_Depends; Note if you remove the Remote_Types pragma and the Shared_Passive pragma from the above example, then this is the case with "regular" Ada programs. That is, Ada does not guarantee that the private part of objects within the same partition cannot be influenced by visible variables in other packages, and if it that's OK within the same partition, why wouldn't it also be OK across different partitions? > If we're going to give up on the safety of Annex E in favor of > expediency, then we should simply delete it from the language. Are we really giving anything up on safety here? Do you have an example in mind to illustrate this? > It would have no remaining value (especially as only one vendor is > supporting the annex; they might as well do as they please since > anything using it isn't portable to another vendor's implementation > anyway). I am hopeful that someday we'll see other implementations of Annex E. Having distributed programming support in the language makes Ada a better language, in my opinion. One could say the same thing about Ada 2005. Even if it is not fully available across all implementations today, the standard exists so that implementers have aim towards creating compilers that someday will speak the same language, hopefully. **************************************************************** From: Randy Brukardt Sent: Wednesday, January 20, 2010 4:29 PM ... > end Test_Depends; Sorry, these objects have the same "shape". I'm talking about the number of components and the like, not some random initialization. > Note if you remove the Remote_Types pragma and the Shared_Passive > pragma from the above example, then this is the case with "regular" > Ada programs. True, but the objects in your example all have the same "shape", just different default initializations. That's not interesting, since you can always explicitly initialize an object to anything you want. Differences in default initializations is not really different than that in explicit initializations. I assumed you were talking about something having to do with constraints and/or discriminants, which *would* be interesting. > That is, Ada does not guarantee that the private part of objects > within the same partition cannot be influenced by visible variables in > other packages, and if it that's OK within the same partition, why > wouldn't it also be OK across different partitions? "Influenced" isn't a problem. Having different constraints is a problem! > > If we're going to give up on the safety of Annex E in favor of > > expediency, then we should simply delete it from the language. > > Are we really giving anything up on safety here? Do you have an > example in mind to illustrate this? OK, I was trying to avoid writing this out. with Ada.Environments; package BB is --pragma Shared_Passive; pragma Preelaborate; Param : Natural := Natural'Value(Ada.Environments.Value ("My_Param")); end BB; private with BB; package AA is pragma Remote_Types; type Foo is tagged limited private; private type Data_Array is array (1..BB.Param); type Foo is tagged limited record Data : Data_Array; end record; end AA; This is the case I thought you were talking about. In this case, the elaboration of type Data_Array depends on the variable Param, which is in a Preelaborable but not shared package. That means that the variable may have different values in each such package (depending on the initialization routine), and thus the elaboration of Data_Array may have a different size in each partition. That would not be good, since the marshalling code would read/write different numbers of elements. This can't happen in a single partition program, as the elaboration is only done once and thus everything is the same size. Note that there is no problem with a Shared_Passive package (as the values would necessarily be the same, and, in this case, withing a Preelaborable package isn't allowed). **************************************************************** From: Bob Duff Sent: Wednesday, January 20, 2010 5:00 PM > OK, I was trying to avoid writing this out. Well, I would find it helpful to see the example we're talking about. This one is illegal, because you can't call Ada.Environments.Value at elab time in a Preelaborate package. (Also, I assume you mean, Environment_Variables, and I assume you mean "of Integer" in the decl of Data_Array.) Could you please fix your example? **************************************************************** From: Randy Brukardt Sent: Wednesday, January 20, 2010 5:45 PM > This one is illegal, because you can't call Ada.Environments.Value at > elab time in a Preelaborate package. (Also, I assume you mean, > Environment_Variables, and I assume you mean "of Integer" in the decl > of Data_Array.) Oh, I forgot about that. > Could you please fix your example? It can't be "fixed", as the whole idea is that the object is initialized to different values before elaboration. It still can be done by changing the variable in some other way, but that would appear to require extra-language means (since no real elaboration is allowed). It appears that objects with different shapes are prevented by the preelaboration rules (I had forgotten that those applied to Remote_Types packages). And apparently Brad was originally confused, as there is no interesting way to use a variable in a Remote_Types private part (and of course it is already allowed in the body) [as previously noted, default expressions that are not evaluated don't count]. Doesn't matter though, as this whole idea isn't going anywhere until Amendment 3: (1) It's too late (the deadline for new ideas was November 3, 2009); (2) We've already got more ideas than we can reasonably put into Amendment 2 (I think we'll need to drop some that we already have, introducing more is a non-starter); (3) It's not important to ensuring portability of Ada programs (there is only one implementation of Annex E; when that changes we can talk). Even ignoring (1), (2) means that new ideas have a very high bar at this point, and (3) means this isn't within a country mile of that bar. ****************************************************************