comp.lang.ada
 help / color / mirror / Atom feed
* Re: 'first of strings returned from a function should be 1?
       [not found] <5rcaqi$le8$1@goanna.cs.rmit.edu.au>
@ 1997-07-26  0:00 ` Matthew Heaney
  1997-07-27  0:00 ` Dale Stanbrough
  1997-07-27  0:00 ` David C. Hoos, Sr.
  2 siblings, 0 replies; 13+ messages in thread
From: Matthew Heaney @ 1997-07-26  0:00 UTC (permalink / raw)



In article <5rcaqi$le8$1@goanna.cs.rmit.edu.au>, Dale Stanbrough
<dale@goanna.cs.rmit.EDU.AU> wrote:

>Should the 'first of a string returned from a function be 1?

For predefined "functions," such a Integer'Image, the resulting string is
defined to have 1 as its lower index bound.  But for user-defined
functions, it's up to the specifier to define the behavior (and yes, when
you write a spec for a function that returns an unconstrained array, then
you should also specify what the defined bounds are).
>
>(Getting at the first character of such a string requires creating
>a declare block...
>
>        declare
>           result_String : constant String := Some_Function(Params);
>           result_char   : constant Character := Result_String(1);
>        begin
>           ...
>
>rather than just...
>
>    if Some_Function(Params)(1) = ...
>
>if this is the case).

A function invokation (and even a type conversion) can serve as a "name,"
therefore your latter formulation is correct.  So no, it's not true that
you have to use a declare block to get the value at a certain index.

However, your program would be incorrect if the string returned by the
function did not have 1 as its lower index bound; Constraint_Error would
get raised.  That's why, for user-defined functions that return an
unconstrained array (as is type Standard.String), you need to specify what
the behavior is.

For example, if I do this:

function To_Uppercase (S : String) return String;
   -- Returns an uppercase string having the same index bounds as S.

I would implement it as follows:

function To_Uppercase (S : String) return String is

   Return_Value : String (S'Range);
begin
   <make return value be uppercase of S>;
   return Return_Value;
end;

However, I might also do this:

function To_Uppercase (S : String) return String;
   -- Returns an uppercase string having a lower index bound of 1.

and implement it like this:

function To_Uppercase (S : String) return String is
  
   Return_Value : String (1 .. S'Length);
begin
   <make Return_Value be uppercase of S>;
   return Return_Value;
end;

The former solution is easier, in this case, because I don't have to
convert from one index to the other, as they are the same.  The latter
implementation requires that I convert from an index of S to the
corresponding index of Return_Value.

If you have a function whose return value has bounds you're unsure of, you
could slide the return value:

declare
   The_Value : constant String := f (...);
   subtype Slid is String (1 .. The_Value'Length);
begin
   if Slid (The_Value) (1) then ...

That's why I was careful to state that a conversion can be a name, which in
turn can be dereferenced.

But of course, Ada's attributes make even that unnecessary:

declare
   The_Value : constant String := f (...);
begin
   if The_Value (The_Value'First) then ...

Realize that this only applies to functions that return unconstrained
arrays.  For a constrained array subtype, the subtype specifies the index
bounds.

You can combine these ideas, and use an array subtype in the
implementation.  For example, to simplify the implementation of the
To_Uppercase function, do this:

function To_Uppercase (S : String) return String;
  -- Returns an uppercase string having lower bound 1.

function To_Uppercase (S : String) return String is

   Return_Value : String (S'Range);
   
   subtype Slid is String (1 .. S'Length);
begin
   <simpler implementation using identical bounds>

  return Slid (Return_Value);
end;

So the short answer to the question, Do functions in Ada return
unconstrained arrays with a lower bound of 1?,  is no.

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




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

* Re: 'first of strings returned from a function should be 1?
       [not found] <5rcaqi$le8$1@goanna.cs.rmit.edu.au>
  1997-07-26  0:00 ` 'first of strings returned from a function should be 1? Matthew Heaney
@ 1997-07-27  0:00 ` Dale Stanbrough
  1997-07-27  0:00 ` David C. Hoos, Sr.
  2 siblings, 0 replies; 13+ messages in thread
From: Dale Stanbrough @ 1997-07-27  0:00 UTC (permalink / raw)



Dale Stanbrough writes:
"	declare
 	   result_String : constant String := Some_Function (Params);
 	   result_char   : constant Character := Result_String (1);
 	begin
"


!I meant to write...

 	declare
 	   result_String : constant String := Some_Function (Params);
 	   result_char   : constant Character := Result_String (Result_String'First);
 	begin

Otherwise the two forms are (essentially) the same.

Thanks for the comments anyway Matthew...


Dale




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

* Re: 'first of strings returned from a function should be 1?
       [not found] <5rcaqi$le8$1@goanna.cs.rmit.edu.au>
  1997-07-26  0:00 ` 'first of strings returned from a function should be 1? Matthew Heaney
  1997-07-27  0:00 ` Dale Stanbrough
@ 1997-07-27  0:00 ` David C. Hoos, Sr.
  1997-07-27  0:00   ` Simon Wright
                     ` (2 more replies)
  2 siblings, 3 replies; 13+ messages in thread
From: David C. Hoos, Sr. @ 1997-07-27  0:00 UTC (permalink / raw)



What's wrong with Result_String (Result_String'first) for getting at the
first character of a function result?

From my own experience, I know that it is easy to write a poor function
returning a string result of which the first subscript is not 1, and I
always make the effort to slice (if necessary) the result into the range 1
. result'length, but if you're using
something you can't change, then something like 
New_Result (1 .. Result_String'length) :=
Result_String(Result_String'first .. result_String'first +
Result_String'length -1)
will do the job.

David C. Hoos, Sr.

Dale Stanbrough <dale@goanna.cs.rmit.EDU.AU> wrote in article
<5rcaqi$le8$1@goanna.cs.rmit.edu.au>...
> I suppose the subject line says it all...
> 
> Should the 'first of a string returned from a function be 1?
> 
> (Getting at the first character of such a string requires creating
> a declare block...
> 
> 	declare
> 	   result_String : constant String := Some_Function(Params);
> 	   result_char   : constant Character := Result_String(1);
> 	begin
> 	   ...
> 
> rather than just...
> 
>     if Some_Function(Params)(1) = ...
> 
> if this is the case).
> 
> Dale
> 




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

* Re: 'first of strings returned from a function should be 1?
  1997-07-27  0:00 ` David C. Hoos, Sr.
  1997-07-27  0:00   ` Simon Wright
@ 1997-07-27  0:00   ` Dale Stanbrough
  1997-07-27  0:00     ` Robert A Duff
  1997-07-27  0:00   ` Matthew Heaney
  2 siblings, 1 reply; 13+ messages in thread
From: Dale Stanbrough @ 1997-07-27  0:00 UTC (permalink / raw)



David C. Hoos writes:

"What's wrong with Result_String (Result_String'first) for getting at the
 first character of a function result?"

Because i wanted to call the function, store the first character and not
declare a local string. I am guessing that a local string would require
extra copying (which i generally try to design out of programs)
from heap to stack, although this may not be the case.

"From my own experience, I know that it is easy to write a poor function
 returning a string result of which the first subscript is not 1, and I
 always make the effort to slice (if necessary) the result into the range 1
 . result'length, but if you're using
 something you can't change, then something like 
 New_Result (1 .. Result_String'length) :=
 Result_String(Result_String'first .. result_String'first +
 Result_String'length -1)
 will do the job."

Yes, this will work, but it also requires copying. The subtype solution
seems better to me.

thanks anyway.

Dale




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

* Re: 'first of strings returned from a function should be 1?
  1997-07-27  0:00 ` David C. Hoos, Sr.
@ 1997-07-27  0:00   ` Simon Wright
  1997-07-27  0:00   ` Dale Stanbrough
  1997-07-27  0:00   ` Matthew Heaney
  2 siblings, 0 replies; 13+ messages in thread
From: Simon Wright @ 1997-07-27  0:00 UTC (permalink / raw)



"David C. Hoos, Sr." <david.c.hoos.sr@ada95.com> writes:

>                                  something like 
> New_Result (1 .. Result_String'length) :=
> Result_String(Result_String'first .. result_String'first +
> Result_String'length -1)
> will do the job.

What about

New_Result (1 .. Result_String'length) := Result_String;

-- 
Simon Wright                        Work Email: simon.j.wright@gecm.com
GEC-Marconi Radar & Defence Systems            Voice: +44(0)1705-701778
Command & Information Systems Divsion            FAX: +44(0)1705-701800




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

* Re: 'first of strings returned from a function should be 1?
  1997-07-27  0:00 ` David C. Hoos, Sr.
  1997-07-27  0:00   ` Simon Wright
  1997-07-27  0:00   ` Dale Stanbrough
@ 1997-07-27  0:00   ` Matthew Heaney
  1997-07-28  0:00     ` Robert A Duff
  2 siblings, 1 reply; 13+ messages in thread
From: Matthew Heaney @ 1997-07-27  0:00 UTC (permalink / raw)



In article <01bc9a76$459c2250$4c8371a5@dhoossr>, "David C. Hoos, Sr."
<david.c.hoos.sr@ada95.com> wrote:


>From my own experience, I know that it is easy to write a poor function
>returning a string result of which the first subscript is not 1, 

Poor is a relative term.  For some abstractions, returning a string whose
lower index is not 1 might make more sense.

In the example I gave, 

function To_Uppercase (S : String) return String;

one could argue that the return value should have the same bounds as the
input string S (which doesn't necessarily have 1 as the lower bound).

Consider a sequence:

generic
   type Sequence_Item is private;
   type Sequence_Item_Array is 
      array (Positive range <>) of Sequence_Item;
package Sequences_G is

   type Root_Sequence is abstract tagged private;

   function Subsequence
     (Sequence : Root_Sequence;
      First           : Positive;
      Last            : Positive) return Sequence_Item_Array;

Surely, the array returned by this function would have First, not 1, as its
lower bound.
     

>and I
>always make the effort to slice (if necessary) the result into the range 1
>. result'length, but if you're using
>something you can't change, then something like 
>New_Result (1 .. Result_String'length) :=
>Result_String(Result_String'first .. result_String'first +
>Result_String'length -1)
>will do the job.

Why not

Result_String'Last, 

instead of 

Result_String'First + Result_String'Length - 1 ?

And why not

   := Result_String 

instead of

   := Result_String (Result_STring'First .. Result_String'Last) ?

Indeed, why bother with the copy at all:

declare
   Result_String : constant String := f (...);
   subtype Slid is String (1 .. Result_String'Length);
begin
   if Slid (Result_String)(1) then

Even if you do decide to make a copy, why not do it in the declarative region:

declare
   Result_String_Unslid : constant String := f (...);
   subtype Slid is String (1 .. Result_String_Unslid'Length);
   Result_String : constant String := Slid (Result_String_Unslid);
begin
   if Result_String (1) ...

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




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

* Re: 'first of strings returned from a function should be 1?
  1997-07-27  0:00   ` Dale Stanbrough
@ 1997-07-27  0:00     ` Robert A Duff
  1997-07-27  0:00       ` Dale Stanbrough
  0 siblings, 1 reply; 13+ messages in thread
From: Robert A Duff @ 1997-07-27  0:00 UTC (permalink / raw)



In article <5rfcs1$i3j$1@goanna.cs.rmit.edu.au>,
Dale Stanbrough  <dale@goanna.cs.rmit.EDU.AU> wrote:
>Because i wanted to call the function, store the first character and not
>declare a local string. I am guessing that a local string would require
>extra copying (which i generally try to design out of programs)
>from heap to stack, although this may not be the case.

I don't get it.  It sounds like you're willing to painstakingly
calculate 387 characters, and then throw away all but one of them.  But
yet you begrudge the copying of them.

What's the real-life example where this makes sense?

- Bob




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

* Re: 'first of strings returned from a function should be 1?
  1997-07-27  0:00     ` Robert A Duff
@ 1997-07-27  0:00       ` Dale Stanbrough
  1997-07-27  0:00         ` Matthew Heaney
  0 siblings, 1 reply; 13+ messages in thread
From: Dale Stanbrough @ 1997-07-27  0:00 UTC (permalink / raw)



Robert A Duff writes:

"I don't get it.  It sounds like you're willing to painstakingly
 calculate 387 characters, and then throw away all but one of them.  But
 yet you begrudge the copying of them.
 
 What's the real-life example where this makes sense?"

For my current situation it doesn't really matter much (i have written a
function that selects a field from a colon (or whatever) separated list
of fields in a string, and i am currently extracting a single character
string), but the more general question came to mind.

If I selected a field, and wanted to check whether a substring existed...

   if Index (Field (Line, 2, ':'), "xxx") = 0 then

Copying the string (yet again) just to pass it to another function didn't
seem to make sense. Perhaps I could also write Field as a procedure returning 
an upper and lower bound to eliminate all copying.

Good point.

Dale




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

* Re: 'first of strings returned from a function should be 1?
  1997-07-27  0:00       ` Dale Stanbrough
@ 1997-07-27  0:00         ` Matthew Heaney
  0 siblings, 0 replies; 13+ messages in thread
From: Matthew Heaney @ 1997-07-27  0:00 UTC (permalink / raw)



In article <5rg99c$pg1$1@goanna.cs.rmit.edu.au>, Dale Stanbrough
<dale@goanna.cs.rmit.EDU.AU> wrote:


>If I selected a field, and wanted to check whether a substring existed...
>
>   if Index (Field (Line, 2, ':'), "xxx") = 0 then
>
>Copying the string (yet again) just to pass it to another function didn't
>seem to make sense. Perhaps I could also write Field as a procedure returning 
>an upper and lower bound to eliminate all copying.

I don't know what you mean either, by "copying the string just to pass it
to another function."  If Field is a function that returns a string, and
you pass it as an argument to another subprogram, on what basis are you
assuming a copy occurs?  Strings (and other arrays and records) are usually
passed by reference.  What's different about your problem?

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




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

* Re: 'first of strings returned from a function should be 1?
  1997-07-27  0:00   ` Matthew Heaney
@ 1997-07-28  0:00     ` Robert A Duff
  1997-07-29  0:00       ` Anonymous
  1997-07-30  0:00       ` Dale Stanbrough
  0 siblings, 2 replies; 13+ messages in thread
From: Robert A Duff @ 1997-07-28  0:00 UTC (permalink / raw)



In article <mheaney-ya023680002707971114240001@news.ni.net>,
Matthew Heaney <mheaney@ni.net> wrote:
>In article <01bc9a76$459c2250$4c8371a5@dhoossr>, "David C. Hoos, Sr."
><david.c.hoos.sr@ada95.com> wrote:
>
>
>>From my own experience, I know that it is easy to write a poor function
>>returning a string result of which the first subscript is not 1, 
>
>Poor is a relative term.  For some abstractions, returning a string whose
>lower index is not 1 might make more sense.

Ada would be a better language if there were a (convenient) way to
specify that the lower bound of an array is fixed, and that the
upper bound is not.  And if the predefined type String used that
feature to specify that the lower bound of all Strings is 1, whereas
the upper bound is different for different strings.

The current situation is error-prone: almost all strings start at 1,
so if you have some code that accidentally makes that assumption, it
will work fine, most of the time, but then will fail in rare cases
(e.g. if somebody decides to pass a slice).  (Bugs that happen all
the time are easy to notice and fix during testing -- bugs that
happen rarely are the ones that leak out to your customers.)

For the vast majoriy of strings, what you care about is the
characters (and how many there are) -- not what the bounds are.
(That's why string comparison ignores the bounds, and just uses the
lengths.  And why Put_Line("Hello, world.") doesn't print out the
bounds!)

>In the example I gave, 
>
>function To_Uppercase (S : String) return String;
>
>one could argue that the return value should have the same bounds as the
>input string S (which doesn't necessarily have 1 as the lower bound).

One could also argue that the result should be 1..whatever.  Or that
the bounds should be an implementation detail of the function, and
the caller should make sure to use 'First and 'Last on the result.
The problem here is that it's not clear what the right answer is.
And you can only tell what choice was made by looking at the body of
that routine.  Or else trust the comments (which probably don't even
exist, and might lie).  If all strings started at 1, then the bounds
of the result of To_Uppercase would *necessarily* match the bounds
of S.

>   function Subsequence
>     (Sequence : Root_Sequence;
>      First           : Positive;
>      Last            : Positive) return Sequence_Item_Array;
>
>Surely, the array returned by this function would have First, not 1, as its
>lower bound.

I disagree.

This is the same argument given in the Ada 83 rationale, for why the
lower bound of S(5..10) is 5.  The problem is that once the slice (or
Subsequence) has been taken, you've just got a String (or sequence).
The user of that String shouldn't have to know that it came from a
slicing operation.  (E.g. consider passing S(5..10) to a procedure.)
IMHO, in:

    X: String := ...;
    ...
    Y: String := X(5..10);

Y is its own string, and its first character should be numbered 1,
just like most other strings.  We shouldn't have to know or care
that it was copied out of the middle of some other string.
(Consider also "Y: String := F(...);", where F says "return
X(5..10);".)

Note that if you fix the lower bound at 1, you have the nice
property that all strings of a given length have matching bounds.
This is useful for looping through a pair of strings, even if the
loop uses 'First rather than hard-coding 1.

Besides, it would be more efficient to fix the lower bound of strings at
1.  Suppose we have a program where the average string length (for
strings in the heap) is 16 characters.  The compiler needs to store *at
least* 8 bytes of dope with each string -- a 50% overhead.  And loops
needs to spend extra time fetching the lower bound, which is almost
always 1.

- Bob

P.S. I don't know what the right answer is to the original question,
which I would paraphrase as "Given that Ada has this problem, should
we work around it by making sure all string-producing code produces
strings with lower bound 1, or by making sure that all
string-consuming code works correctly for any bounds?  Or both?"
All I can say is that the choice should be made as globally as
possible, and that it should be documented.




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

* Re: 'first of strings returned from a function should be 1?
  1997-07-28  0:00     ` Robert A Duff
@ 1997-07-29  0:00       ` Anonymous
  1997-07-30  0:00         ` Robert A Duff
  1997-07-30  0:00       ` Dale Stanbrough
  1 sibling, 1 reply; 13+ messages in thread
From: Anonymous @ 1997-07-29  0:00 UTC (permalink / raw)



<5rcaqi$le8$1@goanna.cs.rmit.edu.au>
<01bc9a76$459c2250$4c8371a5@dhoossr>
<mheaney-ya023680002707971114240001@news.ni.net>

On Mon, 28 Jul 1997 15:54:37 GMT, bobduff@world.std.com (Robert A Duff)
wrote:

> Ada would be a better language if there were a (convenient) way to
> specify that the lower bound of an array is fixed, and that the
> upper bound is not.  And if the predefined type String used that
> feature to specify that the lower bound of all Strings is 1, whereas
> the upper bound is different for different strings.

Given:

procedure P (S : in out String);
..
V : String (1 .. 100);
..
P (V (5 .. 96) );

What happens inside P? Does this part of V have a lower bound of 1
inside P but a lower bound of 5 outside?

Jeff Carter  PGP:1024/440FBE21
My real e-mail address: ( carter @ innocon . com )
"Now go away or I shall taunt you a second time."
Monty Python & the Holy Grail

Posted with Spam Hater - see
http://www.compulink.co.uk/~net-services/spam/




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

* Re: 'first of strings returned from a function should be 1?
  1997-07-28  0:00     ` Robert A Duff
  1997-07-29  0:00       ` Anonymous
@ 1997-07-30  0:00       ` Dale Stanbrough
  1 sibling, 0 replies; 13+ messages in thread
From: Dale Stanbrough @ 1997-07-30  0:00 UTC (permalink / raw)



Anonymous writes:

"Given:
 
 procedure P (S : in out String);
 ..
 V : String (1 .. 100);
 ..
 P (V (5 .. 96) );
 
 What happens inside P? Does this part of V have a lower bound of 1
 inside P but a lower bound of 5 outside?"

yes, the program has to build up a new descriptor anyway, so making
it like this wouldn't be a problem.

dale




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

* Re: 'first of strings returned from a function should be 1?
  1997-07-29  0:00       ` Anonymous
@ 1997-07-30  0:00         ` Robert A Duff
  0 siblings, 0 replies; 13+ messages in thread
From: Robert A Duff @ 1997-07-30  0:00 UTC (permalink / raw)



In article <199707291314.PAA24611@basement.replay.com>,
Anonymous <nobody@REPLAY.COM> wrote:
>procedure P (S : in out String);
>..
>V : String (1 .. 100);
>..
>P (V (5 .. 96) );
>
>What happens inside P? Does this part of V have a lower bound of 1
>inside P but a lower bound of 5 outside?

Not sure what you mean by inside and outside.  There's a single slice,
and the Ada rule is that its lower bound is 5, whereas I claim a better
rule would be that the lower bound of all strings, including this slice,
be 1.  Inside P, saying "S(1) := 'x';" would modify V(5), given this
not-Ada rule.  The point is that P shouldn't have to know it's being
passed a slice of something else -- it just has a sequence of
characters, which it can modify.

- Bob




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

end of thread, other threads:[~1997-07-30  0:00 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <5rcaqi$le8$1@goanna.cs.rmit.edu.au>
1997-07-26  0:00 ` 'first of strings returned from a function should be 1? Matthew Heaney
1997-07-27  0:00 ` Dale Stanbrough
1997-07-27  0:00 ` David C. Hoos, Sr.
1997-07-27  0:00   ` Simon Wright
1997-07-27  0:00   ` Dale Stanbrough
1997-07-27  0:00     ` Robert A Duff
1997-07-27  0:00       ` Dale Stanbrough
1997-07-27  0:00         ` Matthew Heaney
1997-07-27  0:00   ` Matthew Heaney
1997-07-28  0:00     ` Robert A Duff
1997-07-29  0:00       ` Anonymous
1997-07-30  0:00         ` Robert A Duff
1997-07-30  0:00       ` Dale Stanbrough

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