* 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 ` Matthew Heaney ` (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 ` Matthew Heaney 1997-07-28 0:00 ` Robert A Duff 1997-07-27 0:00 ` Dale Stanbrough 1997-07-27 0:00 ` Simon Wright 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 ` 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-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
* 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-27 0:00 ` David C. Hoos, Sr. 1997-07-27 0:00 ` Matthew Heaney @ 1997-07-27 0:00 ` Dale Stanbrough 1997-07-27 0:00 ` Robert A Duff 1997-07-27 0:00 ` Simon Wright 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 ` 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 ` David C. Hoos, Sr. 1997-07-27 0:00 ` Matthew Heaney 1997-07-27 0:00 ` Dale Stanbrough @ 1997-07-27 0:00 ` Simon Wright 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
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 ` 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 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 ` Simon Wright
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox