* Access to aliased string declaration question. @ 1999-06-09 0:00 Rex Reges 1999-06-10 0:00 ` Matthew Heaney 1999-06-10 0:00 ` Robert Dewar 0 siblings, 2 replies; 4+ messages in thread From: Rex Reges @ 1999-06-09 0:00 UTC (permalink / raw) Example program below doesn't compile... with Text_IO ; use Text_IO ; procedure Borg is -- Example of ragged arrays using heap and declared values. -- Create access to unconstrained type string. type String_Access_Type is access all String ; -- Define an array of strings: type String_Array_Type is array ( Positive range <> ) of String_Access_Type ; -- Declare "ragged" arrays of strings... Borg_Strings : String_Array_Type ( 1..3 ) ; Dalek_Strings : String_Array_Type ( 1..3 ) ; -- Create constants for alias access example. -- 123456789112345678921 Static_Dalek_String_1 : aliased String( 1..21 ) := "Resistance is futile." ; Static_Dalek_String_2 : aliased String( 1..12 ) := "Exterminate!" ; Static_Dalek_String_3 : aliased String( 1..12 ) := "Exterminate!" ; begin -- Create the heap strings. Borg_Strings(1) := new String'( "We are the Borg." ); Borg_Strings(2) := new String'( "Resistance is futile." ); Borg_Strings(3) := new String'( "You will be assimilated." ); -- Assign the declared strings. Dalek_Strings := ( 1 => Static_Dalek_String_1'access , 2 => Static_Dalek_String_2'access , 3 => Static_Dalek_String_3'access ) ; -- The Borg versus the Daleks... for I in 1..3 loop Put_Line( "Borg: " & Borg_Strings ( I ).all ) ; Put_Line( "Dalek: " & Dalek_Strings( I ).all ) ; end loop ; end Borg; End of example program. The compilation results for this program are: $ gnatmake borg.adb gcc -c borg.adb borg.adb:36:28: object subtype must statically match designated subtype borg.adb:37:28: object subtype must statically match designated subtype borg.adb:38:28: object subtype must statically match designated subtype gnatmake: "borg.adb" compilation error If I remove the Dalek's string range indices, the program compiles without error: Static_Dalek_String_1 : aliased String := "Resistance is futile." ; Static_Dalek_String_2 : aliased String := "Exterminate!" ; Static_Dalek_String_3 : aliased String := "Exterminate!" ; Why is this so? Shouldn't String_Access_Type be able to point to any string? Rex Reges ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Access to aliased string declaration question. 1999-06-09 0:00 Access to aliased string declaration question Rex Reges @ 1999-06-10 0:00 ` Matthew Heaney 1999-06-10 0:00 ` Matthew Heaney 1999-06-10 0:00 ` Robert Dewar 1 sibling, 1 reply; 4+ messages in thread From: Matthew Heaney @ 1999-06-10 0:00 UTC (permalink / raw) On 9 Jun 1999 20:53, Rex Reges <Rex.R.Reges@Boeing.com> 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 <mailto:matthew_heaney@acm.org> ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Access to aliased string declaration question. 1999-06-10 0:00 ` Matthew Heaney @ 1999-06-10 0:00 ` Matthew Heaney 0 siblings, 0 replies; 4+ messages in thread From: Matthew Heaney @ 1999-06-10 0:00 UTC (permalink / raw) On 10 Jun 1999 04:39, Matthew Heaney <matthew_heaney@acm.org> wrote: > 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. Actually, you don't even need the subtype mark: declare SA : String_Access (S'Range) := S'Access; begin > 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 No subtype mark is needed here either: procedure Op (F, L : Positive) is S : aliased String (F .. L); SA : String_Access (S'Range) := S'Access; begin ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Access to aliased string declaration question. 1999-06-09 0:00 Access to aliased string declaration question Rex Reges 1999-06-10 0:00 ` Matthew Heaney @ 1999-06-10 0:00 ` Robert Dewar 1 sibling, 0 replies; 4+ messages in thread From: Robert Dewar @ 1999-06-10 0:00 UTC (permalink / raw) In article <375ED457.A85A462B@Boeing.com>, Rex Reges <Rex.R.Reges@Boeing.com> wrote: > Example program below doesn't compile... > > with Text_IO ; > use Text_IO ; > > procedure Borg is > > -- Example of ragged arrays using heap and declared values. <<code snipped>> a very common error, common enough that we added some extra warnings to GNAT to help understand the error. Your program now generates warnings like: 23. Static_Dalek_String_3 : aliased String( 1..12 ) := "Exterminate!"; | >>> warning: aliased object has explicit bounds >>> warning: declare with explicit initialization >>> warning: for use with unconstrained access If you give explicit bounds, then you cannot use an unconstrained access. This confusing rule results from the fact that the explicit bounds make the nominal subtype of the object constrained. Just remove the bounds and all will be well. The reason for this (in my opinion highly dubious) bit of language design is to allow the compiler to save space and not generate a template for the bounds in this case. I personally think this was a case of the design being over- influenced by a very minor space optimization issue. Sent via Deja.com http://www.deja.com/ Share what you know. Learn what you don't. ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~1999-06-10 0:00 UTC | newest] Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 1999-06-09 0:00 Access to aliased string declaration question Rex Reges 1999-06-10 0:00 ` Matthew Heaney 1999-06-10 0:00 ` Matthew Heaney 1999-06-10 0:00 ` Robert Dewar
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox