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.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,6433f675cae9b5bc X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 2001-03-30 10:52:16 PST Path: supernews.google.com!sn-xit-03!supernews.com!nntp.cs.ubc.ca!newsfeed.direct.ca!look.ca!newshub2.rdc1.sfba.home.com!news.home.com!news1.sttls1.wa.home.com.POSTED!not-for-mail From: "Mark Lundquist" Newsgroups: comp.lang.ada References: Subject: Re: Allocate an array of a record with a discriminant? X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 5.00.2314.1300 X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2314.1300 Message-ID: Date: Fri, 30 Mar 2001 18:48:52 GMT NNTP-Posting-Host: 24.20.66.55 X-Complaints-To: abuse@home.net X-Trace: news1.sttls1.wa.home.com 985978132 24.20.66.55 (Fri, 30 Mar 2001 10:48:52 PST) NNTP-Posting-Date: Fri, 30 Mar 2001 10:48:52 PST Organization: Excite@Home - The Leader in Broadband http://home.com/faster Xref: supernews.google.com comp.lang.ada:6266 Date: 2001-03-30T18:48:52+00:00 List-Id: Hey Joe, Joe wrote in message news:tc1ghv4o7s23e2@corp.supernews.co.uk... > Dear all, > > I'd appreciate it greatly if any of you could answer the following question. > > Basically, I want to create an array of English words. The following > information will be given before the words are typed in, _but_ not before > runtime: > > - the maximum length of any one word (the Max_Length variable will contain > it) > - the number of words to be given (Num_Words) OK, I'm with ya... > > A word would be described by something like the following type: > > type Word (Max_Length : Integer) is > record > Length : Integer; > S : String (1 .. Max_Length); > end record; Fair enough... > > As I understand it, using discriminants with arrays is not possible such as: > > type Words (Max_Word_Length : Integer) is array (Natural range <>) of Word > (Max_Word_Length); You're right, an array type can't be a discriminated type (remember, a discriminant is a special kind of component, and while that fits into the idea of a record -- which has named components of arbitrary types -- it doesn't fit into the idea of an array, where all the components are of the same type and all are indexable over a range). > > How is it possible to allocate space for an array of type "Word" where all > are of the same "Word.Length" which is "Max_Length" at runtime? > > Keep in mind that Max_Length and Num_Words are given at runtime, not before. Easy. I'll show you two ways to do it... (Disclaimer: I haven't run these examples through a compiler, so some tweakage may be required :-) The first way looks like this: function Get_Num_Words return Natural is begin -- Prompt victim for number of words and take input; -- I dummied it up to return a hardcoded value -- return 10; end Get_Num_Words; function Get_Max_Word_Length return Natural is begin -- Prompt victim for number of words and take input; -- I dummied it up to return a hardcoded value -- return 32; end Get_Max_Word_Length; -- -- A "word". -- Max_Word_Length : constant Natural := Get_Max_Word_Length; type Word is record Length : Natural; S : String (1 .. Max_Word_Length); end record; -- -- An array of "words". -- Num_Words : constant Natural := Get_Num_Words; type Words is array (1 .. Num_Words) of Word; OK, notice the following: 1) Here we have the program "doing stuff" (getting user input) *before* all the type definitions are elaborated. You can do that! 2) No discriminant is required for type Word. That should make sense intuitively, since as you said, all objects of the type have the same "max length". Discriminants are for when *not* all values of the type have the same "whatever". 3) For type Words, we could also have declared it unconstrained: type Words is array (Natural range <>) of Word; more like in your example, and constrained it at the declaration of the object of that type. It doesn't make any difference. Now, let's make a slight change... you can take the Length field of type Word, and pull it out as a discriminant! Here's how that looks: subtype Word_Length is Natural range 1 .. Max_Word_Length; type Word (Length : Word_Length := Max_Word_Length) is record S : String (1 .. Length); end record; Get it? We're using the discriminant for the *length* of each individual word, not the "max length" like in your example. Things to note: 1) The discriminant has a default value. 2) We used our own constrained subtype for the subtype of the discriminant These two things make it possible to declare objects (and components) of type Word, without including a discriminant constraint in the object declaration! This is called an "unconstrained object", and it it's only allowed if the discriminant has a default value (to satisfy the language rule that a discriminant must always be initialized). Unconstrained objects have the unique property that the discriminant can be changed as the result of a "whole-value assignment" to the object -- more on that in a bit. But first note that because no discriminant constraint is required, you can declare your array exactly as in the first example I gave: type Words is array (1 .. Num_Words) of Word; Now each element of Words is an unconstrained object. How much storage is reserved for each element? Enough to hold the largest possible value (just like you wanted!). How do we know what that is? It's determined by the subtype of the discriminant. That's why we had to define our own subtype for this; if we had written type Word (Length : Natural := Max_Word_Length) is record ... Then the largest possible value would have a string of length Natural'Last, so you would most likely get an exception (like Storage_Error) at run-time when elaborating the declaration of an object of the type. Notice that in this application, the value for the discriminant default does not matter! Since we're just going to change the discriminant values of all these objects anyway, we could have just as well said type Word (Length : Word_Length := 0) is record ... It's the subtype that determines how much storage is allocated, not the discriminant default. Now, how do you change the discriminant of an unconstrained object? With a "whole-value assignment", like this: Words (1) := (Length => 6, "foobar"); You would probably make things more convenient by doing something like this: function To_Word (S : String) return Word is begin return Word'(S'Length, S); end To_Word; Words (1) := To_Word ("foobar"); -- let the compiler worry about the length One nice thing about making the word length a discriminant is that each Word's string component now is sized just right for that word, so you don't have to slice it to get the right substring. So instead of something like Put_Line (Words(I).S(1 .. Words(I).Length)); you can just say Put_Line (Words(I).S); Hope this helps... As some others pointed out, there are other (maybe better) ways to skin this cat, like using Ada.Strings.Bounded or Ada.Strings.Unbounded. But I thought you might find it helpful to know how to skin it in the particular way that you asked about :-) Best, Mark Lundquist Rational Software