From: Warren on
I am looking for some sound Ada ('05) advice on
a design issue, concerning strings.

In my basic interpreter, I permit the end user
to choose the array subscript ranges just like
in Ada.

But this includes strings, whereas in Ada one
generally just uses the String type, with
its positive subscript values.

I would find it convenient in the interpreter to
use a string type with an Integer range for Basic
string variables instead:

type String_Type is
array(Integer range <>) of Character;

This allows subscripts to range negative to
positive. The reason for this approach is that
any dynamically allocated string would also
carry this "bounds" info with it, saving me
from having to manage it separately.

However, I'll need to convert them back to
normal Ada Strings in order to manipulate
and print them etc.

The following snippet highlights the challenge:

with Ada.Text_IO; use Ada.Text_IO;

procedure M is

type String_Type is array(Integer range <>) of Character;

S : String_Type := "Abc.";
T : String(1..4);
begin

T := String(S);
Put_Line(T);

end M;

$ gnatmake -Wall m.adb
gcc -c -Wall m.adb
m.adb:11:17: warning: value out of range of type "Standard.String"
m.adb:11:17: warning: "Constraint_Error" will be raised at run time
gnatbind -x m.ali
gnatlink m.ali

Is there a simple way to "slide" my String_Type
into a normal Ada String array?

Or must I do this in a custom function for the
purpose, character by character?

Warren
From: stefan-lucks on
On Fri, 16 Apr 2010, Warren wrote:

> procedure M is
>
> type String_Type is array(Integer range <>) of Character;
>
> S : String_Type := "Abc.";
> T : String(1..4);
> begin
> T := String(S);
-- this raises Constraint_Error
> Put_Line(T);
>
> end M;

Convert S into a variable of type String_Type with String-compatible
bounds, and then convert that variable into a String:

S : String_Type := "Abc.";
T : String_Type(1 .. S'Length) := S;
U : String(1 .. S'Length);
begin
U := String(T); Put_Line(U); -- or just Put_Line(String(T));

If you have to do that frequently, use an appropriate function (without
any need to copy the String-like thing character by character):

function To_String(S: String_Type) return String is
X: String_Type(1 .. S'Length) := S;
begin
return String(X);
end To_String;



I hope that helps!

Stefan


--
------ Stefan Lucks -- Bauhaus-University Weimar -- Germany ------
Stefan dot Lucks at uni minus weimar dot de
------ I love the taste of Cryptanalysis in the morning! ------

From: J-P. Rosen on
stefan-lucks(a)see-the.signature a �crit :
> Convert S into a variable of type String_Type with String-compatible
> bounds, and then convert that variable into a String:
>
> S : String_Type := "Abc.";
> T : String_Type(1 .. S'Length) := S;
> U : String(1 .. S'Length);
> begin
> U := String(T); Put_Line(U); -- or just Put_Line(String(T));
>
No need for intermediate copy, just use an appropriate subtype:

S : String_Type := "Abc.";
T : String(1..4);
subtype Slide is String_type (T'Range);
begin
T := String(Slide(S));

--
---------------------------------------------------------
J-P. Rosen (rosen(a)adalog.fr)
Visit Adalog's web site at http://www.adalog.fr
From: Charmed Snark on
J-P. Rosen expounded in news:hqahb1$tnm$1(a)news.eternal-september.org:

> stefan-lucks(a)see-the.signature a �crit :
>> Convert S into a variable of type String_Type with String-compatible
>> bounds, and then convert that variable into a String:
>>
>> S : String_Type := "Abc.";
>> T : String_Type(1 .. S'Length) := S;
>> U : String(1 .. S'Length);
>> begin
>> U := String(T); Put_Line(U); -- or just Put_Line(String(T));
>>
> No need for intermediate copy, just use an appropriate subtype:
>
> S : String_Type := "Abc.";
> T : String(1..4);
> subtype Slide is String_type (T'Range);
> begin
> T := String(Slide(S));

Great- thanks. Fast service too :)

Warren
From: Adam Beneschan on
On Apr 16, 1:29 pm, "J-P. Rosen" <ro...(a)adalog.fr> wrote:
> stefan-lu...(a)see-the.signature a écrit :> Convert S into a variable of type String_Type with String-compatible
> > bounds, and then convert that variable into a String:
>
> >     S : String_Type := "Abc.";
> >     T : String_Type(1 .. S'Length) := S;
> >     U : String(1 .. S'Length);
> >   begin
> >      U := String(T); Put_Line(U);  -- or just Put_Line(String(T));
>
> No need for intermediate copy, just use an appropriate subtype:
>
>    S : String_Type := "Abc.";
>    T : String(1..4);
>    subtype Slide is String_type (T'Range);
> begin
>    T := String(Slide(S));

You don't even need two type conversions:

S : String_Type := "Abc.";
subtype String_Subtype is String(1..S'Length);
T : String_Subtype;
-- T : String(1..4); -- this works too
begin
T := String_Subtype(S);

Sometimes reading the manual helps (especially if you know where to
look). 4.6(37-38) says about array type conversions:

* If the target subtype is a constrained array subtype, then a check
is made that the length of each dimension of the value of the operand
equals the length of the corresponding dimension of the target
subtype. The bounds of the result are those of the target subtype.
* If the target subtype is an unconstrained array subtype, then the
bounds of the result are obtained by converting each bound of the
value of the operand to the corresponding index type of the target
type. For each nonnull index range, a check is made that the bounds of
the range belong to the corresponding index subtype.

So if we're converting to a constrained subtype (like String_Subtype),
it just makes sure the length is the same on each dimension; while if
we're converting to an unconstrained subtype (like String), then each
bound is expected to be the same. So we solve the problem by making
the type conversion target a constrained subtype.

-- Adam