Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Array of Strings

213 views
Skip to first unread message

jedivaughn

unread,
Sep 13, 2008, 10:18:14 AM9/13/08
to
Hi everyone,

I'm having trouble making a array of type string. can some one show me
how to do this. I've tried type letters is array (Integer range <>) of
String; but I get error "unconstrained element type in array
declaration". what am I doing wrong?

Thanks,

John

Ludovic Brenta

unread,
Sep 13, 2008, 10:32:54 AM9/13/08
to

The type String is unconstrained because you don't know the size of
the strings at compile time. Therefore you cannot put Strings in an
array. You can however create:

- an array of fixed-size strings; for this you need a subtype e.g.

subtype Constrained_String is String (1 .. 10);
type Array_Of_Constrained_Strings is
array (Positive range <>) of Constrained_String;

- an array of access values to Strings e.g.

type String_Access is access String;
type Array_Of_String_Accesses is array (Positive range <>) of String_Access;

(!this is the most error-prone method!)

- an array of Ada.Strings.Unbounded.Unbounded_Strings e.g.

type Array_Of_Unbouded_Strings is
array (Positive range <>) of Ada.Strings.Unbounded.Unbounded_String;

- an array of Ada.Strings.Bounded.Bounded_Strings similar to the above
but you also need to specify the maximum size

HTH

--
Ludovic Brenta.

anon

unread,
Sep 13, 2008, 8:11:23 PM9/13/08
to
Here os an example
type Day_Array is array ( Monday..Sunday ) of
String ( 1..3 ) ;
type Date_Array is array ( integer range <> ) of
String ( 1..3 ) ;

SDay : Day_Array := ( "Mon", "Tue", "Wed", "Thu",
"Fri", "Sat", "Sun" ) ;

SMonth : Date_Array ( 1..12 ) := ( "Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug",
"Sep", "Oct", "nov", "Dec" ) ;

Per Sandberg

unread,
Sep 14, 2008, 5:45:57 AM9/14/08
to
You could also go for the Ada containers approach and get vector
semantics's.

with Ada.Containers.Indefinite_Vectors;
procedure Demo is
package String_Vectors is new Ada.Containers.Indefinite_Vectors
(Natural, String);
V : String_Vectors.Vector;
begin
V.Append ("Tell Me");
V.Append ("Tell You");
end Demo;

/Per

Adam Beneschan

unread,
Sep 15, 2008, 10:54:10 AM9/15/08
to

One of the things that needs to be impressed upon newer Ada
programmers is that Ada's String type is *not* a varying-length
string. Some languages have varying-length strings built into them,
like BASIC and Perl; you can just assign a 2-character string into a
string variable, and later change it to an 80-character string, and
later to an empty (zero-length) string, and so on, without worrying
too much. (I believe there are many other languages that also have
this sort of string type.) Ada's String type is not like this. A
String variable has a particular length and that length cannot be
changed. (Maybe it was a mistake to name it "String" because of the
potential for confusion.)

Ludovic already mentioned Bounded_String and Unbounded_String which
were added in Ada 95 to fill that hole.

-- Adam

jedivaughn

unread,
Sep 16, 2008, 7:56:12 PM9/16/08
to
Thanks to all. Got it to work great. And I agree Adam it does need to
be stressed more about string length. Coming from C++ I had no idea
about a set length string.


Thanks,
John

jedivaughn

unread,
Sep 23, 2008, 10:07:17 AM9/23/08
to
If I wanted to make a package that made the array generic how would I
go about doing this. this is what I have which isn't working.

generic

type Element_Type is (<>);
type range1 is (<>);


package list is
type letters is private;

private
type letters is array (range1) of Element_Type;

end list;


and then in the main program I want

subtype range2 is integer range 1..25;
subtype str_length is string (1..25);

package List1 is new List(Element_Type => str_length, range1 =>
range2 );

when I try to compile the main program I get "expect discrete type in
instantiation of "Element_Type""

what am I doing wrong?

Thanks,
John

Message has been deleted

mockturtle

unread,
Sep 23, 2008, 10:30:37 AM9/23/08
to

According to RM 12.5.2 "type Element_Type is (<>);" means that
Element_Type
is a discrete type. I guess that you want something like
"type Element_Type is private;" (I did not check)

> Thanks,
> John

Adam Beneschan

unread,
Sep 23, 2008, 10:41:06 AM9/23/08
to

Yes, that's right. When you declare a generic formal type (a "type"
declaration between the keyword "generic" and the beginning of the
package or procedure declaration), there are several ways to declare
the type, and the different ways control what sorts of types you can
use to instantiate the generic. Here's an incomplete rundown:

type T is private; -- T can be any nonlimited type except an
-- unconstrained type
type T(<>) is private; -- T can be any nonlimited type
type T is (<>); -- T must be discrete, i.e. integer or
-- enumeration
type T is range <>; -- T must be a signed (non-modular) integer
type
type T is mod <>; -- T must be a modular type
type T is digits <>; -- T must be a floating-point type
type T is delta <>; -- T must be a fixed-point type, not decimal
fixed
type T is delta <> digits <>; -- T must be a decimal fixed-point type

You can also declare formal array types, access types, and derived
types. Also, the "private" generic formal declarations can have
"tagged" and/or "limited" keywords applied. See the manual (12.5) for
more information.

-- Adam


Ludovic Brenta

unread,
Sep 23, 2008, 10:47:23 AM9/23/08
to

That's correct.

To the OP: out of curiosity, why don't you use Ada.Containers.Vectors?
Even if you have good reason not to use this package, you will benefit
from reading its spec as a source of inspiration (aka "best
practices").

Also see http://en.wikibooks.org/wiki/Ada_Programming/Generics

--
Ludovic Brenta.

Jeffrey R. Carter

unread,
Sep 23, 2008, 2:51:42 PM9/23/08
to
jedivaughn wrote:
> If I wanted to make a package that made the array generic how would I
> go about doing this. this is what I have which isn't working.
>
> generic
>
> type Element_Type is (<>);

This specifies that the actual for Element_Type must a discrete type, as the
error msg indicates.

> type range1 is (<>);
>
>
> package list is
> type letters is private;
>
> private
> type letters is array (range1) of Element_Type;
>
> end list;
>
>
> and then in the main program I want
>
> subtype range2 is integer range 1..25;
> subtype str_length is string (1..25);

Presumably you want Element_Type to be private, which allows any non-limited
type you can declare an object of without an initialization. I presume you're
doing this to learn about generics, since what you have here doesn't do anything
worthwhile.

There is also a way to define your component type as an array type:

generic -- List
type Element_Component is private;
type Element_Index is (<>);
type Element is array (Element_Index) of Element_Component;
type Letters_Index is (<>);
package List is
type Letters is private;
private -- List
type Letters is array (Letters_Index) of Element;
end List;

This is more restrictive than private.

--
Jeff Carter
"Sir Lancelot saves Sir Gallahad from almost certain temptation."
Monty Python & the Holy Grail
69

jedivaughn

unread,
Sep 24, 2008, 8:00:47 AM9/24/08
to
can anyone show me an example of using this to put string data into
the array and pulling it back out.

generic

type Element_Type is (<>); -- everything in the list is of this
type
type range_array is (<>); -- the index of the array if of this
type

-- ads file of package
package final is
type recd is private;


private
type listy is array(range_array) of element_type;
type recd is record
str: listy;
str_counter: integer;
where: integer;
end record;

end final;

-- adb file of main program
with ada.text_IO, ada.integer_text_IO, final;

procedure List_package is
subtype int_range is integer range 1..25;

package list is new final (element_type=> character,
range_array => int_range);
package list2 is new final (element_type => integer,
range_array => int_range);
the : list.recd;
the2 : list2.recd;
begin


end list_package;

every time I look for a place on how to do this they are using integer
data. so how do you do it with string data from a file?

Thanks,
John

Message has been deleted

Adam Beneschan

unread,
Sep 24, 2008, 10:36:43 AM9/24/08
to

I don't think you're providing enough details. Presumably, when
you're defining your generic package Final, you don't want to define
*just* a private type, because you can't do anything with it. You
also want your package to define some operations (procedures and
functions) on that type. I.e. what is a "recd", from the point of
view of some other Ada code outside of Final; and what would you want
that code to do a recd if you had one? I'm guessing that if you
answer those questions, you'll probably also have the answer to your
first question.

-- Adam


John McCormick

unread,
Sep 24, 2008, 11:13:12 AM9/24/08
to
In a bit of a self serving suggestion, have a look at Chapter 4 of my
Freshman level textbook "Ada Plus Data Structures: An Object-Oriented
Approach", Dale and McCormick, Jones and Bartlett, 2007. This chapter
is devoted to the use and implementation of strings: Fixed-Length,
Bounded-Length, and Unbounded-Length. You can check it out for free
on Google Books.

John

On Sep 24, 7:00 am, jedivaughn <jedivaugh...@gmail.com> wrote:
> can anyone show me an example of using this to put string data into
> the array and pulling it back out.
>

> Thanks,
> John

Jeffrey R. Carter

unread,
Sep 24, 2008, 1:18:28 PM9/24/08
to
jedivaughn wrote:
> can anyone show me an example of using this to put string data into
> the array and pulling it back out.
>
> generic
>
> type Element_Type is (<>); -- everything in the list is of this
> type
> type range_array is (<>); -- the index of the array if of this
> type
>
> -- ads file of package
> package final is
> type recd is private;
>
>
> private

To a client of an instantiation of Final, there is no array. There's only type
Recd. The operations defined for an object of type Recd for the client include
assignment, "=", "/=", in, not in, and some attributes such as 'Size and
'Address. Have I missed any?

Since there are no operations to put or get string data into a Recd or an
instantiation of Final, I cannot show you how to do that.

(OK, I could show you how to do it using unchecked conversion or an address
overlay, but that's not what you're asking about.)

--
Jeff Carter
"Crucifixion's a doddle."
Monty Python's Life of Brian
82

jedivaughn

unread,
Sep 28, 2008, 8:24:11 AM9/28/08
to
This is going to be a long post but hopefully I'll make myself clearer
this time. I finally got everything set up in my package and it works
just fine. however one of the operations that I'm trying to do on the
package is an append. after appending to the list I want to make sure
the list is still in order. so I have to make comparisons with the <
or > operators. however, ada give's me the error: "final.adb:22:34:
there is no applicable operator ">" for private type "Element_Type"
defined at final.ads:3."

Here is my package's .ads file

generic

type Element_Type is private; -- everything in the list is of this
type
type range_array is (<>); -- the index of the array is of this
type

package final is
type recd is tagged private;

function construct return recd;
procedure append (inthe : in out recd; char : in element_type);
procedure insert (inthe : in out recd; char : in element_type);
procedure remove (inthe : in out recd; char : in element_type);
function get_next(lst: in recd) return element_type;

where: integer := 0;


private
type listy is array(range_array) of element_type;

type recd is tagged record
str: listy;
str_counter: range_array;
order : boolean := true;
end record;

end final;

my package's .adb file


with ada.text_IO, ada.integer_text_IO;

package body final is
function construct return recd is
inthe:recd;
begin
inthe.str_counter := range_array'first;
where := 0;
return inthe;
end construct;

procedure append (inthe : in out recd; char : in element_type)
is
i : integer := 1;
begin
inthe.str(inthe.str_counter) := char;
inthe.str_counter := range_array'succ(inthe.str_counter);
if inthe.str_counter = range_array'val(1) then
null;
else
loopy:
for i in range_array'val(1)..inthe.str_counter loop
if (inthe.str(i)) > (inthe.str(i)) then
inthe.order := false;
exit loopy;
end if;
end loop loopy;
end if;
end append;

procedure insert (inthe : in out recd; char : in element_type)
is
temp : element_type;
where2 : range_array;
begin
where2 := range_array'first;
if inthe.order = true then
if inthe.str_counter <= where2 then
null;
else
loopy :
for i in range_array'val(1)..inthe.str_counter loop
if (inthe.str(where2)) <
(inthe.str(range_array'succ(where2))) then
temp := inthe.str(where2);
inthe.str(where2) :=
inthe.str(range_array'succ(where2));
inthe.str(range_array'succ(where2)) := temp;
end if;
where2 := range_array'succ(where2);
end loop loopy;
end if;
end if;
end insert;
procedure remove (inthe : in out recd; char : in element_type)
is
begin
null;
end remove;

function get_next(lst: in recd) return element_type is
begin
where := where + 1;
return lst.str(range_array'val(where));
end get_next;

end final;

and my my_main program's .adb


with ada.text_IO, ada.integer_text_IO, final;

procedure List_package is
subtype int_range is integer range 1..25;

subtype str_range is integer range 1..5;
subtype str25 is string (1..5);
package list is new final (element_type=>str25, range_array =>
str_range);


package list2 is new final (element_type => integer,
range_array => int_range);
the : list.recd;
the2 : list2.recd;

procedure iny is
filbert : ada.text_IO.file_type;
char : integer;
begin
the2 := list2.construct;
ada.text_IO.open(filbert, ada.text_IO.in_file,
"intdata.txt");
ada.integer_text_IO.get(file => filbert, item => char);
list2.append(the2,char);
ada.integer_text_IO.get(file => filbert, item => char);
list2.append(the2,char);
ada.integer_text_IO.put(list2.get_next(the2));
ada.integer_text_IO.put(list2.get_next(the2));
ada.text_IO.new_line;
ada.text_IO.close(filbert);
end iny;

procedure sny is
filbert : ada.text_IO.file_type;
char : string (1..5);
widy : integer := 5;
begin
the := list.construct;
ada.text_IO.open(filbert, ada.text_IO.in_file,
"strdata.txt");
ada.text_IO.get_line(file => filbert, item => char, last =>
widy);
list.append(the,char);
ada.text_IO.put(list.get_next(the));
ada.text_IO.close(filbert);
end sny;

begin
iny;
sny;
end list_package;


can anyone tell me why I don't have the basic operators for my generic
list? and also how do I get them. this seems like a very important
part of all data types.

Thanks,
John

Message has been deleted

mockturtle

unread,
Sep 28, 2008, 9:01:33 AM9/28/08
to

jedivaughn ha scritto:

> This is going to be a long post but hopefully I'll make myself clearer
> this time. I finally got everything set up in my package and it works
> just fine. however one of the operations that I'm trying to do on the
> package is an append. after appending to the list I want to make sure
> the list is still in order. so I have to make comparisons with the <
> or > operators. however, ada give's me the error: "final.adb:22:34:
> there is no applicable operator ">" for private type "Element_Type"
> defined at final.ads:3."
>
> Here is my package's .ads file
>
> generic
>
> type Element_Type is private; -- everything in the list is of this
> type
> type range_array is (<>); -- the index of the array is of this
> type
>
> package final is

(snip)

You must tell to the compiler that comparison is defined
for the type you are going to use for Element_Type since
the compiler does not know that you are going to use
strings as Element_Type (for example, you could use for
Element_Type some "record" which has no "natural" comparison
operator). You declare that Element_Type has comparison
operators by adding after the "type Element_Type..."

with function ">"(left, right : Element_Type) return Boolean is <>;

Few remarks:
1. I have no Ada compiler at hand, so I cannot 101% grant that the
line above is correct, although I would be surprised if it wasn't.

2. It is not necessary that the function parameters have name
"left" and "right" (quite obvious)

3. The "is <>" tells the compiler to use as default any
visible ">" operator with the required interface. This allows you
to use the package with strings without esplicitely specifying
the comparison operator.

My answer is necessarly brief. If you want more details, I suggest
to [brace yourself :-) and] have look to chapter 12 (especially
section
12.6 "Formal subprograms") of the [ mytical/beloved/behated, choose
one] reference manual

http://www.adaic.com/standards/05rm/html/RM-TTL.html


jedivaughn

unread,
Sep 28, 2008, 1:08:50 PM9/28/08
to
where would I code

"with function ">"(left, right : Element_Type) return Boolean is <>; "

I assume in the generic part of the .ads file. do I have to change the
lines


package list is new final (element_type=>str25, range_array =>
str_range);

package list2 is new final (element_type => integer,
range_array => int_range);

Thank for all the help,
John Morman

Jeffrey R. Carter

unread,
Sep 28, 2008, 3:00:14 PM9/28/08
to
jedivaughn wrote:
> This is going to be a long post but hopefully I'll make myself clearer
> this time. I finally got everything set up in my package and it works
> just fine. however one of the operations that I'm trying to do on the
> package is an append. after appending to the list I want to make sure
> the list is still in order. so I have to make comparisons with the <
> or > operators. however, ada give's me the error: "final.adb:22:34:
> there is no applicable operator ">" for private type "Element_Type"
> defined at final.ads:3."
>
> Here is my package's .ads file
>
> generic
>
> type Element_Type is private; -- everything in the list is of this
> type

You should think of the generic formal part (the part between "generic" and
"package") as a specification: it specifies what the generic needs from its
clients in order to do what it does.

The various kinds of formal parameters to a generic specify different things.
For example

type T1 is range <>;

specifies that the generic needs all the features and operations of a signed
integer type. This includes assignment and conversion from other numeric types.

type T2 is (<>);

specifies that the generic needs a discrete type. This includes integer types
(signed and unsigned) and enumeration types. The set of features and operations
used by the generic is naturally different from those for T1.

type T3 is private;

specifies that the generic needs to be able to create objects of the type
without initialization, or declare composite types with components of the type.
It specifies that the generic will use assignment of values of the type, and the
"=" and "/=" operations. That is just about all the generic needs from the type,
unless it explicitly specifies that it needs additional operations on the type
in the form of generic formal subprogram parameters operating on the type:

generic
type T is private;

with function "-" (Left : in T; Right : in T) return T is <>;
package P is ...

In your case, it sounds as if you need

with function ">" ...

--
Jeff Carter
"People called Romanes, they go the house?"


Monty Python's Life of Brian

79

mockturtle

unread,
Sep 29, 2008, 7:14:42 AM9/29/08
to

jedivaughn ha scritto:

In this case it is not necessary to change the "...is new..." lines
since
(1) your types (str25 and integer) have a predefined ">" operator and
(2) you used the subprogram_default part "is <>". If your comparison
was implemented as function (say) Greater_Than, the you would had to
add in the instantiation lines something like

">" => Greater_Than

Adam Beneschan

unread,
Sep 29, 2008, 11:51:12 AM9/29/08
to
On Sep 28, 12:00 pm, "Jeffrey R. Carter"
<spam.jrcarter....@spam.acm.org> wrote:

> In your case, it sounds as if you need
>
> with function ">" ...

One other thing: It looks like, in the body of your generic, you're
using both < and >. (I assume you did get errors about both operators
and just didn't mention it in your post?) You will need to say either

with function ">" (Left, Right...

or

with function "<" (Left, Right...

in the generic formal part as the Mock Turtle and the Mad Ha.... um, I
mean Jeff have pointed out. But please note that defining one won't
automatically give you the other (there is no rule in the language
that says B<A is the same as A>B for all types, although it's true for
predefined types and one-dimensional arrays of predefined types). So
you will either need to fix the body so it consistently uses either <
or >, but not both; or you'll need to include "with function" clauses
for *both* operators. My own preference would be for the first
option; if you're instantiating with a string type or other predefined
types, it doesn't matter that much since the compiler will
automatically define both for you anyway; but if you're going to use
some user-defined record type where the user will need to write their
own "<" or less-than operator, having two "with function" clauses
would force them to write subroutines for both operators, which
shouldn't be necessary IMHO.

-- Adam

0 new messages