comp.lang.ada
 help / color / mirror / Atom feed
* Allocate an array of a record with a discriminant?
@ 2001-03-27 15:41 Joe
  2001-03-27 20:22 ` Robert A Duff
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Joe @ 2001-03-27 15:41 UTC (permalink / raw)


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)

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;

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);

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.

Thanks in advance,

Joe






^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: Allocate an array of a record with a discriminant?
@ 2001-03-27 19:44 Beard, Frank
  0 siblings, 0 replies; 6+ messages in thread
From: Beard, Frank @ 2001-03-27 19:44 UTC (permalink / raw)
  To: 'comp.lang.ada@ada.eu.org'

There a couple ways I can think of off the top of my head.

1) Use a declare block;

   procedure XYZ is
      ...
   begin
      ...
      --+ Prompt for Max_Length and Num_Words
      ...
      declare
         subtype Constrained_Word is Word(Max_Length);
         type Word_Array_Type is array (1..Num_Words) of Constrained_Word;
         Word_Array : Word_Array_Type;
      begin
         ...
         --+ Input the Words and do your processing.
         ...
      end;
      ...
   end XYZ;

The problem with this method is you have to stay within the declare block,
which is fine if it's your main program and pass it down to subprograms.


2) Use Access types.

   procedure XYZ is
      ...
      type Word_Access_Type is access Word;
      type Word_Array_Type is array (Natural range <>) of Word_Access_Type;
      type Word_Array_Access_Type is access Word_Array_Type;
      ...
      Word_Access       : Word_Access_Type;
      Word_Array_Access : Word_Array_Access_Type;
      ...
   begin
      ...
      --+ Prompt for Max_Length and Num_Words
      ...  
      Word_Array_Access := new Word_Array_Type(Num_Words);
      for I in 1 .. Num_Words loop
         ...
         Word_Array_Accss(I) := new Word(Max_Length);
         ...
      end loop;
      ...
      --+ Input the Words and do your processing.
      ...
   end XYZ;

Frank

PS.

It's a good idea to default you values, such as

   type Word (Max_Length : Integer) is
      record
         Length : Integer := 0;
         S : String (1 .. Max_Length) := (others => ' ');
      end record;

And if you default Max_Lenth, as in:

   type Word (Max_Length : Integer := 100) is
      record
         Length : Integer := 0;
         S : String (1 .. Max_Length) := (others => ' ');
      end record;

You could use the record directly in the Word_Array_Type I 
declared above, except that using Integer as the base range
will cause the compiler to reserve 2147483647 characters
as the maximum possible variant of each element of the array.
Which will probably result in Storage_Error.  If you want to
go that route, you need to define your own type with a smaller
range.

-----Original Message-----
From: Joe [mailto:sorry@no.email]
Sent: Tuesday, March 27, 2001 10:42 AM
To: comp.lang.ada@ada.eu.org
Subject: Allocate an array of a record with a discriminant?


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)

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;

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);

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.

Thanks in advance,

Joe



_______________________________________________
comp.lang.ada mailing list
comp.lang.ada@ada.eu.org
http://ada.eu.org/mailman/listinfo/comp.lang.ada




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Allocate an array of a record with a discriminant?
  2001-03-27 15:41 Joe
@ 2001-03-27 20:22 ` Robert A Duff
  2001-03-27 21:11 ` tmoran
  2001-03-30 18:48 ` Mark Lundquist
  2 siblings, 0 replies; 6+ messages in thread
From: Robert A Duff @ 2001-03-27 20:22 UTC (permalink / raw)


"Joe" <sorry@no.email> writes:

> 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)

You could use Ada.Strings.Unbounded, and then you wouldn't care what the
max length is.

- Bob



^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: Allocate an array of a record with a discriminant?
  2001-03-27 15:41 Joe
  2001-03-27 20:22 ` Robert A Duff
@ 2001-03-27 21:11 ` tmoran
  2001-03-30 18:48 ` Mark Lundquist
  2 siblings, 0 replies; 6+ messages in thread
From: tmoran @ 2001-03-27 21:11 UTC (permalink / raw)


Do you want to allocate an array of a record with a discriminant,
or do you want to create and access a list of words?  If the
latter, you might do better to make a package with a spec
along the lines of:

  Overflow : exception;  -- Attempt to Add too many words,
                         -- or too many characters of words.
  Nonesuch : exception;  -- Attempt to Get non-existent ID.

  type Word_Counts is range 0 .. ???
  subtype Word_Indices is Word_Counts range 1 .. Word_Counts'last;

  function Count return Word_Counts;
  -- return number of stored words.

  function Add(S : in Word) return Word_Indices;
  -- Add to store.  Return new index.
  -- Raise Overflow if too many or too long words.

  function Get_Length(Index : in Word_Indices) return Natural;
  -- raise Nonesuch if no such word.

  function Get(Index : in Word_Indices) return Word;
  -- raise Nonesuch if no such word.

  ... anything else that's needed

which can be easily implemented by storing the words as successive
characters in a single big string, and using an array of start
indices to let you quickly get the n-th word.



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Allocate an array of a record with a discriminant?
  2001-03-27 15:41 Joe
  2001-03-27 20:22 ` Robert A Duff
  2001-03-27 21:11 ` tmoran
@ 2001-03-30 18:48 ` Mark Lundquist
  2001-03-31  4:22   ` Robert A Duff
  2 siblings, 1 reply; 6+ messages in thread
From: Mark Lundquist @ 2001-03-30 18:48 UTC (permalink / raw)


Hey Joe,

Joe <sorry@no.email> 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






^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Allocate an array of a record with a discriminant?
  2001-03-30 18:48 ` Mark Lundquist
@ 2001-03-31  4:22   ` Robert A Duff
  0 siblings, 0 replies; 6+ messages in thread
From: Robert A Duff @ 2001-03-31  4:22 UTC (permalink / raw)


"Mark Lundquist" <mark@rational.com> writes:

> > 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).

I think it makes perfect sense for arrays to have discriminants.  It
just happens that Ada doesn't allow it.  In fact, I would say that if
array bounds and discriminants were treated as the same thing, the
language would be simplified.

I realize this doesn't answer the original question -- but you did that
quite nicely in the rest of your posting (which I snipped).

- Bob



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2001-03-31  4:22 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-03-27 19:44 Allocate an array of a record with a discriminant? Beard, Frank
  -- strict thread matches above, loose matches on Subject: below --
2001-03-27 15:41 Joe
2001-03-27 20:22 ` Robert A Duff
2001-03-27 21:11 ` tmoran
2001-03-30 18:48 ` Mark Lundquist
2001-03-31  4:22   ` Robert A Duff

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