From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.3 required=5.0 tests=BAYES_00,INVALID_MSGID autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,543daa919438f82e X-Google-Attributes: gid103376,public From: Matthew Heaney Subject: Re: Access to aliased string declaration question. Date: 1999/06/10 Message-ID: #1/1 X-Deja-AN: 487780746 References: <375ED457.A85A462B@Boeing.com> NNTP-Posting-Date: Wed, 09 Jun 1999 21:39:18 PDT Newsgroups: comp.lang.ada Date: 1999-06-10T00:00:00+00:00 List-Id: On 9 Jun 1999 20:53, Rex Reges wrote: > Why is this so? Shouldn't String_Access_Type be able to point to any > string? Not exactly. An access object of type String_Access_Type can only point to /unconstrained/ strings. You have to understand how arrays and array pointers are implemented. Associated with an unconstrained array object is a little data structure called a "string descriptor" or "dope vector," that stores the indices of the array and the length of the array. When you deference an access object that designates a unconstrained string object, the compiler (er, run-time system) uses the dope vector to determine how long the array is, or to determine which physical characters are being accessed. For example, if S is an access object, then the dereference: Put_Line (S.all); would look up the length of the string designated by S in the dope vector associated with that string object. Pointers to unconstrained arrays always do this: consult the dope vector. However, for constrained array objects, no dope vector is necessary, because you know everything about the string object at the point of its declaration. For example: S : String (1 .. 10); You know the length and bounds of S, so there is no need for any additional data structure (ie a dope vector) to store the info. Likewise for a constrained array access type: type String_Access is access all String (1 .. 10); S : String_Access; When you deference S, you know up front what the length and indices of the designed string object are, so you don't need to consult a dope vector. So we see that an access object that designates an unconstrained array object is fundamentally different from an access object that designates a constrained array object. The former must consult a dope vector, the latter does not. Now you might argue that you might as well generate a dope vector for this declaration, even though it's constrained: Static_Dalek_String_1 : aliased String (1 .. 21) := "Resistance is futile."; If you did so, then you'd be able to designate this string object using either kind of access type. However, this would generate an extra 8 bytes (for the dope vector) for each string object, all in the hope that maybe the object will be designated by an unconstrained access object. But Ada is a systems programming language, and systems programmers don't take kindly to this kind of code bloat. They want to pay only for what they need, and having to carry around extra dope vector baggage when it isn't needed for the problem at hand would not be acceptable. Ada puts you, the programmer, in the driver's seat: if /you/ want a dope vector, then /you/ declare the object like this, without bounds: Static_Dalek_String_1 : aliased String := "Resistance is futile."; If you want no dope vector, then declare it as you did earlier, with explicit bounds. Yes, this must seem like a pain in the ass. I'm not unsympathetic. But it's just a consequence of the fact that Ada is for programming systems, and you have to let the /programmer/ decide where and when he wants to pay storage cost. It's not all that bad, either. Sometimes you can have it both ways by declaring a dynamic (or maybe static) access subtype: type String_Access is access all String; S : aliased String (1 .. 10); ... declare subtype S_Access is String_Access (S'Range); SA : S_Access := S'Access; begin Here we declare a subtype that points only to strings having the bounds of object S. This is a constrained string object, designed by an access object whose (base) type is unconstrained. This works even if the bounds are determined at run-time: procedure Op (F, L : Positive) is S : aliased String (F .. L); subtype S_Access is String_Access (F .. L); -- or S'Range SA : S_Access := S'Access; begin Post another message if any of this is unclear. This is one of the more esoteric features of Ada. Matt