comp.lang.ada
 help / color / mirror / Atom feed
From: Robert A Duff <bobduff@shell01.TheWorld.com>
Subject: Re: Discriminant name must be alone
Date: Sat, 21 Dec 2002 23:08:52 GMT
Date: 2002-12-21T23:08:52+00:00	[thread overview]
Message-ID: <wccadiz0y2j.fsf@shell01.TheWorld.com> (raw)
In-Reply-To: mailman.1040497983.21337.comp.lang.ada@ada.eu.org

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



  reply	other threads:[~2002-12-21 23:08 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-12-21 19:22 Discriminant name must be alone Michal Nowak
2002-12-21 23:08 ` Robert A Duff [this message]
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
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox