From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: 103376,db88d0444fafe8eb X-Google-Attributes: gid103376,public X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news1.google.com!news3.google.com!news.glorb.com!newscon02.news.prodigy.com!newscon06.news.prodigy.com!prodigy.net!newsfeed-00.mathworks.com!nntp.TheWorld.com!not-for-mail From: Robert A Duff Newsgroups: comp.lang.ada Subject: Re: Surprise in array concatenation Date: 06 Sep 2005 11:30:07 -0400 Organization: The World Public Access UNIX, Brookline, MA Message-ID: References: <1125610942.747981.280770@f14g2000cwb.googlegroups.com> NNTP-Posting-Host: shell01.theworld.com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: pcls4.std.com 1126020608 31207 192.74.137.71 (6 Sep 2005 15:30:08 GMT) X-Complaints-To: abuse@TheWorld.com NNTP-Posting-Date: Tue, 6 Sep 2005 15:30:08 +0000 (UTC) User-Agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.2 Xref: g2news1.google.com comp.lang.ada:4475 Date: 2005-09-06T11:30:07-04:00 List-Id: "Bob Spooner" writes: > "Robert A Duff" wrote in message > news:wccoe77nq3l.fsf@shell01.TheWorld.com... > > tmoran@acm.org writes: > > > snip... > > > > Slices should slide to the lower bound. The Ada rule breaks > > abstraction: > > So if I pass a subprogram a slice of an array indexed by an enumeration type > then the mapping of the values to the enumeration type should change? No. Let me explain more clearly what I meant: In Ada, for a given array type, you can choose to fix both bounds, or neither. You cannot choose to fix the lower bound (for all objects of the type), but not the upper bound. I think the programmer should have all four choices of fixing the bounds for an array type. Part of the problem here is that "array" is a fairly low-level abstraction. When the index is an enumeration type, you're usually using the array to represent a higher-level concept -- a "mapping" from enum values to whatever. When you declare something like String, on the other hand, you're using the array to represent a different higher-level concept -- a "sequence of characters". "Sequence" and "mapping" are different (though related) concepts. For a sequence, the indices have no inherent meaning -- they just represent the order in which the elements appear in the sequence. So I don't have trouble with the idea that slices of strings should slide the bounds to 1..Length, whereas slices of a "mapping" sort of array should not. > > > > procedure P(X: String) is > > begin > > ... > > end P; > > > > Y: String := "Hello, world!"; > > > > P(Y(3..4)); > > > > Inside the body of P, X is just a String -- we don't (or shouldn't) know > > that it's a substring of Y. So we can't possibly make any sense (inside > > P) of the fact that X'First = 3. Index 3 from what? > > > > If I ran the circus, X'First would be 1. > > > > But that would make String a special case of an array if you allow other > arrays to start with a value other than the first value of the index type. > Yet another thing we would have to remember... Yes, you have to remember, for each array type, whether the programmer who wrote it intended it as a sequence or a mapping. If a sequence, you have to remember whether they fixed the lower bound at zero or one (or they did some other weird thing, presumably for good reason). > > > > I wouldn't insist on starting _all_ arrays at 1, but I think it makes > > sense for _many_ arrays, including String. > > > > Many other special cases to remember as well? Yes, String is just one example where it makes sense to fix the lower bound at 1. Just like for a linked list, you have to remember whether it's circular or null-terminated or .... > snip... > > > > - Bob > > In my view, the abstraction that is important here is that of the array > rather than that of the subprogram seeing a slice as always beginning with > Index'first. The characteristics of the abstraction of an array should be as > consistent in Ada as possible. As consistent as possible, but no more so. ;-) Enumerations and integers have much in common (that's why they're both part of the class of discrete types). But there are some important differences, and I don't think you can get away with pretending they're the same thing. We should avoid _gratuitous_ inconsistencies. >... While having the first value of a String and > whatever types of arrays you think are appropriate always be the first value > of the index type would save some memory and computation time,... It would also reduce the number of bugs, I think. (In particular, it would prevent the confusion shown by the original example at the start of this thread.) We know how to write code that correctly handles all Strings, including those with bounds 100..101, but Ada should be designed to prevent accidental errors, even in the presence of fallible programmers. >... Ada is one of > the few languages where the array is a powerful and safe abstraction. It is > therefore much more useful than in other languages, making consistency of > behavior all the more important and, I think, worth the price in > computation. To make arrays robust and safe in C type languages,... I'm comparing Ada to an Ada-like language that is slightly different (and, I claim, slightly better). I'm not comparing it to C. Ada arrays are obviously far superior to C arrays in many ways! >... for > instance, involves adding a lot more baggage than an extra integer value and > a little bit of computation done transparently by the compiler. It's not always transparent. For example, Dmitry pointed out the example of a procedure that takes two arrays, and wants to perform some operation on pairs of elements from each. If you can assume that the two arrays have equal lower bounds, the source code becomes much simpler (and therefore less error prone). I'll grant you that you must then remember which array types allow that assumption. But that's already an issue, since you can fix _both_ bounds in Ada (and you have to remember you did that). For example: type Char_Mapping is array(Character) of Character; procedure P(X, Y: Character_Mapping) is begin for I in Character loop -- or, equivalently, Char_Mapping'Range Do_Something(X(I), Y(I)); I claim that's perfectly reasonable code to write -- yet it would be wrong if Char_Mapping had not fixed the bounds (that is, if it said "range <>"). - Bob