* Discriminant name must be alone @ 2002-12-21 19:22 Michal Nowak 2002-12-21 23:08 ` Robert A Duff 0 siblings, 1 reply; 6+ messages in thread From: Michal Nowak @ 2002-12-21 19:22 UTC (permalink / raw) Hello all, Digging around (teaching myself and experimenting with Ada) I wandered to RM 3.8 (12): "A name that denotes a noninherited discriminant is allowed within the declaration of the type, but not within the discriminant_part. If the discriminant is used to define the constraint of a component, the bounds of an entry family, or the constraint of the parent subtype in a derived_type_definition then its name shall appear alone as a direct_name (not as part of a larger expression or expanded name). A discriminant shall not be used to define the constraint of a scalar component." At this point (maybe later I will get deeper in other uses) I'm thinking about using a discriminant to define the constraint of a component. This rule forbids me to do something like this: type R (Start_Ind : Positive) is record Table : Some_Array_Type (1 .. Start_Ind + 10); end record; and like this: type R (Start_Ind : Positive) is record Table : Some_Array_Type (Start_Ind .. Start_Ind + 10); end record; I may live with this, but I don't like to blindly follow the rules, I'm a bit more curious :-). AARM (12a): "Reason: The penultimate restriction simplifies implementation, and allows the outer discriminant and the inner discriminant or bound to possibly share storage." gives me some explanation to this. In fact, in my first example, if the array was constrained by (1 .. Start_Ind), Start_Ind may be shared by record and array, but if it is (1 .. Start_Ind + 10) it cannot. In the second example Start_Ind may be shared, even if it breaks the rule two times, but that's only a specific example and does not shows my point. My questions: Why is this rule so restrictive? Is the (potential) possibility or simpler implementation only reason for it? Maybe there are historical (I may be too young to know them - I'm just freshly after studies) or so? If someone has any pointers I'll be glad to read them. From the other side - if the possibility of shared storage is the only one, maybe it would be reasonable to weaken this rule in next Ada revision, to allow uses like above? So the memory usage depends on how discriminants are used. Are there any uses (examples), where it is reasonable to keep this rule in current form? Regards, - Michal -- ----------------------------------------------------------------- -- ___ _ -- / _ \ | | I Choose Ada: -- | |_| | ___| | _____ The Most Trusted Name in Software (TM) -- | _ | | __ | | __ | -- |_| |_| |_____|_ |_____|_ http://www.adaic.org/whyada/choose.html -- -- ----------------------------------------------------------------- ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Discriminant name must be alone 2002-12-21 19:22 Discriminant name must be alone Michal Nowak @ 2002-12-21 23:08 ` Robert A Duff 2002-12-23 11:21 ` Dmitry A. Kazakov 2002-12-25 14:29 ` Michal Nowak 0 siblings, 2 replies; 6+ messages in thread From: Robert A Duff @ 2002-12-21 23:08 UTC (permalink / raw) Michal Nowak <vinnie@inetia.pl> writes: > Hello all, > > Digging around (teaching myself and experimenting with Ada) > I wandered to RM 3.8 (12): I suggest using a textbook (perhaps Barnes) to learn Ada, rather than the RM. Unless you're very comfortable reading all the legalese in the RM (and AARM)... > "A name that denotes a noninherited discriminant is allowed within > the declaration of the type, but not within the discriminant_part. > If the discriminant is used to define the constraint of a component, > the bounds of an entry family, or the constraint of the parent subtype > in a derived_type_definition then its name shall appear alone as a > direct_name (not as part of a larger expression or expanded name). > A discriminant shall not be used to define the constraint of a scalar > component." > > At this point (maybe later I will get deeper in other uses) I'm > thinking about using a discriminant to define the constraint of > a component. This rule forbids me to do something like this: > > type R (Start_Ind : Positive) is > record > Table : Some_Array_Type (1 .. Start_Ind + 10); > end record; > > and like this: > > type R (Start_Ind : Positive) is > record > Table : Some_Array_Type (Start_Ind .. Start_Ind + 10); > end record; That's right. Those are illegal. > I may live with this, but I don't like to blindly follow > the rules, I'm a bit more curious :-). AARM (12a): > "Reason: The penultimate restriction simplifies implementation, > and allows the outer discriminant and the inner discriminant or > bound to possibly share storage." > gives me some explanation to this. In fact, in my first example, > if the array was constrained by (1 .. Start_Ind), Start_Ind may > be shared by record and array, but if it is (1 .. Start_Ind + 10) > it cannot. In the second example Start_Ind may be shared, even > if it breaks the rule two times, but that's only a specific example > and does not shows my point. > My questions: Why is this rule so restrictive? Is the (potential) > possibility or simpler implementation only reason for it? The implementation issue is not just "potential". It really does simplify implementation to know that the bound can be computed by a simple fetch of the discriminant. >...Maybe > there are historical (I may be too young to know them - I'm just > freshly after studies) or so? If someone has any pointers I'll be > glad to read them. > From the other side - if the possibility of shared storage is > the only one, maybe it would be reasonable to weaken this > rule in next Ada revision, to allow uses like above? So the > memory usage depends on how discriminants are used. Are there > any uses (examples), where it is reasonable to keep this rule > in current form? Most uses have no problem with the current rule. The usual thing is that the discriminant is the upper bound of an array. Not 10 less than the upper bound, or some other convolution. However, I have run into a few cases where I would like to do what you're suggesting here. For example, I wrote a "storage pool" type, where the private part defined the storage as an array of machine words. The allocated types were known to be always word aligned, and always a multiple of word size. The array of words makes alignment easy, and the Allocate procedure can simply return 'Address of one of the array components. But I wanted the client to specify the size in Storage_Elements. So the array would have to be: Storage: Word_Array(0..(Size_In_Bytes-1)/4); -- Illegal! where Size_In_Bytes is the discriminant. Or something like that. I think the main problem with allowing that (besides what the AARM mentions) is that if you allow arbitrary expressions referring to discriminants, you have to worry about when that expression is evaluated. Suppose that expression is "F(Size_In_Bytes)", where F is some function that might have side effects. If it has side effects, it might return a different answer each time it's called. I suppose one answer is to say that the expression is evaluated whenever a value of the record type is created. The value of that expression must be saved as "dope" -- a hidden record component created by the compiler. If it has side effects, that's the programmer's problem. This would be the first case where a compiler is required to store dope. Some compilers store dope, but it's never required. Another answer is, "forbid side effects in those expressions", so the compiler can evaluate those expressions whenever it likes. Ada has no such mechanism, currently. To provide such a mechanism, each function would have to declare (on the spec) what variables it meddles with -- as in SPARK. If the expression "Start_Ind + 10" is allowed, then surely you should be allowed to call a function that does "return Start_Ind + 10;". So I think your suggestion is reasonable, but would require a substantial change to the language and to compilers, and is only useful in rare cases, so is unlikely to happen. - Bob ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Discriminant name must be alone 2002-12-21 23:08 ` Robert A Duff @ 2002-12-23 11:21 ` Dmitry A. Kazakov 2002-12-23 14:00 ` Robert A Duff 2002-12-25 14:29 ` Michal Nowak 1 sibling, 1 reply; 6+ messages in thread From: Dmitry A. Kazakov @ 2002-12-23 11:21 UTC (permalink / raw) Robert A Duff wrote: > However, I have run into a few cases where I would like to do what > you're suggesting here. For example, I wrote a "storage pool" type, > where the private part defined the storage as an array of machine words. > The allocated types were known to be always word aligned, and always a > multiple of word size. The array of words makes alignment easy, and the > Allocate procedure can simply return 'Address of one of the array > components. But I wanted the client to specify the size in > Storage_Elements. So the array would have to be: > > Storage: Word_Array(0..(Size_In_Bytes-1)/4); -- Illegal! > > where Size_In_Bytes is the discriminant. Or something like that. > > I think the main problem with allowing that (besides what the AARM > mentions) is that if you allow arbitrary expressions referring to > discriminants, you have to worry about when that expression is > evaluated. Suppose that expression is "F(Size_In_Bytes)", where F is > some function that might have side effects. If it has side effects, it > might return a different answer each time it's called. > > I suppose one answer is to say that the expression is evaluated whenever > a value of the record type is created. The value of that expression > must be saved as "dope" -- a hidden record component created by the > compiler. If it has side effects, that's the programmer's problem. > This would be the first case where a compiler is required to store > dope. Some compilers store dope, but it's never required. > > Another answer is, "forbid side effects in those expressions", so the > compiler can evaluate those expressions whenever it likes. Ada has no > such mechanism, currently. To provide such a mechanism, each function > would have to declare (on the spec) what variables it meddles with -- > as in SPARK. If the expression "Start_Ind + 10" is allowed, then surely > you should be allowed to call a function that does "return Start_Ind + > 10;". There is a third answer: "user-defined constructors". Should you have a user-defined constructor for a discriminated type, you could evaluate its discriminants during object construction, which would have same effect as if they were expressions (with the arguments provided by the constructor's argument list). User-defined constructors could also solve the "assignment problem", because an assignment can be easily generated out of copy-constructor. -- Regards, Dmitry A. Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Discriminant name must be alone 2002-12-23 11:21 ` Dmitry A. Kazakov @ 2002-12-23 14:00 ` Robert A Duff 2002-12-24 11:16 ` Dmitry A. Kazakov 0 siblings, 1 reply; 6+ messages in thread From: Robert A Duff @ 2002-12-23 14:00 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > There is a third answer: "user-defined constructors". What do you mean by "user-defined constructors"? How do they differ from functions? And how do they allow nested constraints to depend upon arbitrary expressions involving discriminants? - Bob ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Discriminant name must be alone 2002-12-23 14:00 ` Robert A Duff @ 2002-12-24 11:16 ` Dmitry A. Kazakov 0 siblings, 0 replies; 6+ messages in thread From: Dmitry A. Kazakov @ 2002-12-24 11:16 UTC (permalink / raw) Robert A Duff wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >> There is a third answer: "user-defined constructors". > > What do you mean by "user-defined constructors"? How do they differ > from functions? A function returns some object. To use it you must have an assignment. This would not work for limited types. A constructor returns nothing. For type Buffer (Length : Positive) is ...; Buffer (*) could be viewed as a "call to constructor". Constructor works even if Buffer is limited: X : Buffer (12); > And how do they allow nested constraints to depend > upon arbitrary expressions involving discriminants? Presently we have only predefined "constructors" with the parameters = discriminats. Let we have an ability to define a constructor with other parameters. Then it would evaluate the discriminants from that parameters. Further, a discriminated type could be declared with <> as the discriminant to hide the true disriminants in the private part making them an implementation detail. I have a vague idea how to provide constructors for Ada, but I rather start a separate thread for it. -- Regards, Dmitry A. Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Discriminant name must be alone 2002-12-21 23:08 ` Robert A Duff 2002-12-23 11:21 ` Dmitry A. Kazakov @ 2002-12-25 14:29 ` Michal Nowak 1 sibling, 0 replies; 6+ messages in thread From: Michal Nowak @ 2002-12-25 14:29 UTC (permalink / raw) On 2002-12-21 at 23:08 Robert A Duff wrote: >Michal Nowak <vinnie@inetia.pl> writes: > >> Hello all, >> >> Digging around (teaching myself and experimenting with Ada) >> I wandered to RM 3.8 (12): > >I suggest using a textbook (perhaps Barnes) to learn Ada, rather than >the RM. Unless you're very comfortable reading all the legalese in the >RM (and AARM)... That's OK, I got Cohen's superior "Ada as a Second Language". The rule I was referring to is described in point 9.2.4 (Allowable use of discriminants), but there was no explanation of internal matters and why it is like that. > >The implementation issue is not just "potential". >It really does simplify implementation to know that the bound >can be computed by a simple fetch of the discriminant. > [snip some of my questions] > >Most uses have no problem with the current rule. The usual thing is >that the discriminant is the upper bound of an array. Not 10 less than >the upper bound, or some other convolution. > >However, I have run into a few cases where I would like to do what >you're suggesting here. For example, I wrote a "storage pool" type, >where the private part defined the storage as an array of machine words. >The allocated types were known to be always word aligned, and always a >multiple of word size. The array of words makes alignment easy, and the >Allocate procedure can simply return 'Address of one of the array >components. But I wanted the client to specify the size in >Storage_Elements. So the array would have to be: > > Storage: Word_Array(0..(Size_In_Bytes-1)/4); -- Illegal! > >where Size_In_Bytes is the discriminant. Or something like that. I forget to mention, that I had immutable records in mind, this issue is more complicated with mutable records. I think one time I wanted an array, which was a component of record, to start at specified index, but the discriminant was Size. It was impossible to compute ending bound. >I think the main problem with allowing that (besides what the AARM >mentions) is that if you allow arbitrary expressions referring to >discriminants, you have to worry about when that expression is >evaluated. Suppose that expression is "F(Size_In_Bytes)", where F is >some function that might have side effects. If it has side effects, it >might return a different answer each time it's called. > >I suppose one answer is to say that the expression is evaluated whenever >a value of the record type is created. The value of that expression >must be saved as "dope" -- a hidden record component created by the >compiler. If it has side effects, that's the programmer's problem. >This would be the first case where a compiler is required to store >dope. Some compilers store dope, but it's never required. Now I get the point. Thank you for answer and explanations, Merry Christmas, - Michal -- ----------------------------------------------------------------- -- * ___ * _' ' * ` * ` * ' . -- / _ \ ' * | | * * * ~*~ -- | |_| | ___| | * _____ ` * ` * * ` i/:\i -- | _ *| | __ | | __' | * i/`:'\i -- |_| |_| |____*|_ |_____|_ Christmas with Ada: ` i/`':`'\i -- * ' http://www.autopen.com/OTANBAUM.shtml '^^^I^^^' -- ----------------------------------------------------------------- ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2002-12-25 14:29 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2002-12-21 19:22 Discriminant name must be alone Michal Nowak 2002-12-21 23:08 ` Robert A Duff 2002-12-23 11:21 ` Dmitry A. Kazakov 2002-12-23 14:00 ` Robert A Duff 2002-12-24 11:16 ` Dmitry A. Kazakov 2002-12-25 14:29 ` Michal Nowak
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox