maart@cs.vu.nl (Maarten Litmaath) (07/14/89)
According to the pANS structs can be
- assigned
- returned
- used as function arguments
but they cannot be COMPARED, right? Very annoying.
The reason appears to be internal padding, whose contents aren't specified.
Thus the following won't work:
struct foo {
char bar;
int baz;
double zork;
} mork, mindy;
...
puts(bcmp((char *) &mork, (char *) &mindy, sizeof mork) == 0 ?
"equal" : "unequal");
To compare the 2 structs, one now has to check each field oneself:
puts(mork.bar == mindy.bar && mork.baz == mindy.baz
&& mork.zork == mindy.zork ? "equal" : "unequal");
Why does the PROGRAMMER have to go through all that trouble?
I just want to say:
puts(mork == mindy ? "equal" : "unequal");
Is the ANSI committee trying to tell us the compiler cannot transform the
equality test into the correct member-by-member comparison code?
--
"... a lap-top Cray-2 with builtin |Maarten Litmaath @ VU Amsterdam:
cold fusion power supply" (Colin Dente) |maart@cs.vu.nl, mcvax!botter!maart
henry@utzoo.uucp (Henry Spencer) (07/14/89)
In article <2874@solo3.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes: >Why does the PROGRAMMER have to go through all that trouble? >I just want to say: > > puts(mork == mindy ? "equal" : "unequal"); > >Is the ANSI committee trying to tell us the compiler cannot transform the >equality test into the correct member-by-member comparison code? Yes. Think about unions. Or pointers (do you compare the pointers or what they point at?). The compiler just doesn't have enough information. -- $10 million equals 18 PM | Henry Spencer at U of Toronto Zoology (Pentagon-Minutes). -Tom Neff | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
gwyn@smoke.BRL.MIL (Doug Gwyn) (07/15/89)
In article <2874@solo3.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes: >Is the ANSI committee trying to tell us the compiler cannot transform the >equality test into the correct member-by-member comparison code? No, but apart from the padding issue it is not clear what would constitute "equality" in practice; memberwise comparison would seldom be what one really wanted. Consider char* members, for example; probably struct equality in such a case should use the equivalent of strcmp() on those members. Floating-point equality tests are usually meaningless (except sometimes when one of the operands is precisely zero). Union members pose yet another problem. And so on. Given such pratical problems, and that a programmer can perform this test another way, and that it would be an "invention", X3J11 chose not to require support for aggregate equality testing. There were an immense number of suggestions for such linguistic enhancements received by X3J11, as listed in the introduction to each official public review response document. If there is much interest, I could post the list in order to give you a better appreciation of why such suggestions were routinely rejected.
njk@freja.diku.dk (Niels J|rgen Kruse) (07/15/89)
henry@utzoo.uucp (Henry Spencer) writes: >In article <2874@solo3.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes: >>Why does the PROGRAMMER have to go through all that trouble? >>I just want to say: >> puts(mork == mindy ? "equal" : "unequal"); >>Is the ANSI committee trying to tell us the compiler cannot transform the >>equality test into the correct member-by-member comparison code? >Yes. Think about unions. Or pointers (do you compare the pointers or >what they point at?). The compiler just doesn't have enough information. Just like the compiler doesn't have enough information to initialize a union, right? ! A simple rule like comparing first members of unions and the pointers themselves would work nicely in a lot of cases and match the way initialization works. Or comparison of structs with inconvenient members could just be outlawed, which wouldn't reduce the usefullness much. Or perhaps better, inconvenient members could just be ignored, leaving them for the programmer to handle separately. -- Niels J|rgen Kruse Email njk@diku.dk Mail Tustrupvej 7, 2 tv, 2720 Vanlose, Denmark
henry@utzoo.uucp (Henry Spencer) (07/18/89)
In article <167@ssp1.idca.tds.philips.nl> roelof@idca.tds.PHILIPS.nl (R. Vuurboom) writes: >>It's also not a particularly good idea: suppose I change to a polar >>form, where the representation of a given >>complex number is not unique? > >Henry, this is cheating :-). If somebody comes along and changes the >representation of an int while I'm not looking nobody expects the >two values (old representation vs new representation) to compare equal. Not quite what I was getting at. The point of polar representation is that member-by-member comparison does not dependably get the right answer! Equality comparison on polar representation requires range reduction on the angle first. This leads again to the need for C++, where you can define the comparison operation to be arbitrarily complex. -- $10 million equals 18 PM | Henry Spencer at U of Toronto Zoology (Pentagon-Minutes). -Tom Neff | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
bbadger@x102c.harris-atd.com (Badger BA 64810) (07/18/89)
In article <1989Jul18.020424.2392@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: >In article <167@ssp1.idca.tds.philips.nl> roelof@idca.tds.PHILIPS.nl (R. Vuurboom) writes: >>>It's also not a particularly good idea: suppose I change to a polar >>>form, where the representation of a given >>>complex number is not unique? >> >>Henry, this is cheating :-). If somebody comes along and changes the >>representation of an int while I'm not looking nobody expects the >>two values (old representation vs new representation) to compare equal. > >Not quite what I was getting at. The point of polar representation is >that member-by-member comparison does not dependably get the right answer! >Equality comparison on polar representation requires range reduction on >the angle first. This leads again to the need for C++, where you can >define the comparison operation to be arbitrarily complex. >-- >$10 million equals 18 PM | Henry Spencer at U of Toronto Zoology >(Pentagon-Minutes). -Tom Neff | uunet!attcan!utzoo!henry henry@zoo.toronto.edu Sure, you _may_ run into special cases, but is this any reason to leave out a useful operation? Other languages, such as Ada (Oh no! The A-word!), provide for comparison of composite objects (records in Ada correspond to structs in C). Of course there should be caveats about padding data being compared. Also unions should only be compared to another union or object which is *actually using* the same representation. (That is, given: union lf_t {long l; float f} lf_a, lf_b; lf_a.l = 10; lf_b.f = 10.0; we should probably not be testing (lf_a == lf_b), but rather (lf_a.l == (long) lf_b.f).) However, the fact remains that either simple ``compare all bytes'' or an expansion to compare all struct members recursively, would be a simple extension which could be quite useful. Bernard A. Badger Jr. 407/984-6385 |``Use the Source, Luke!'' Secure Computer Products |``Get a LIFE!'' -- J.H. Conway Harris GISD, Melbourne, FL 32902 |Buddy, can you paradigm? Internet: bbadger%x102c@trantor.harris-atd.com|'s/./&&/g' Tom sed expansively.
roelof@idca.tds.PHILIPS.nl (R. Vuurboom) (07/18/89)
In article <1989Jul18.020424.2392@utzoo.uucp| henry@utzoo.uucp (Henry Spencer) writes: | |Not quite what I was getting at. The point of polar representation is |that member-by-member comparison does not dependably get the right answer! |Equality comparison on polar representation requires range reduction on |the angle first. This leads again to the need for C++, where you can |define the comparison operation to be arbitrarily complex. No need to be arbitrary...polar or rectangular will do nicely :-) -- Its a thin red line (and spelling error) between boring and borish. Roelof Vuurboom SSP/V3 Philips TDS Apeldoorn, The Netherlands +31 55 432226 domain: roelof@idca.tds.philips.nl uucp: ...!mcvax!philapd!roelof
guy@auspex.auspex.com (Guy Harris) (07/20/89)
>Sure, you _may_ run into special cases, but is this any reason to leave out >a useful operation? Well, it depends on how useful it *really* is; given enough "special cases", it may be that the only cases where it *is* useful are special cases, in which case you can whip up a macro to do the comparison. >Other languages, such as Ada (Oh no! The A-word!), provide for comparison >of composite objects (records in Ada correspond to structs in C). So how does Ada define comparison of records? >Of course there should be caveats about padding data being compared. I.e., "padding data gets compared"? That doesn't sound like all that useful an operation to me; in order to be useful, I'd have to zero out structures on e.g. the stack. >Also unions should only be compared to another union or object >which is *actually using* the same representation. (That is, given: > union lf_t {long l; float f} lf_a, lf_b; > lf_a.l = 10; > lf_b.f = 10.0; >we should probably not be testing (lf_a == lf_b), but rather >(lf_a.l == (long) lf_b.f).) Fine, so how is the compiler to know to do that? C unions are not discriminated unions; there's nothing in the union itself to indicate which member is being used. >However, the fact remains that either simple ``compare all bytes'' or >an expansion to compare all struct members recursively, would be a simple >extension which could be quite useful. Simple "compare all bytes" is certainly simple; how useful it is is another question, given that comparing padding bytes is simply wrong, unless you *guarantee* that they're always going to have some "standard" value that gets in the way. You still haven't indicated how unions are to be compared, so an expansion to compare all struct members recursively would fail if any such members were unions. And, once again, I'll point out that pointer comparison may or may not be what you want, either. In other words, comparison might be "simple" in a restricted sense, but nobody's proven that in that "simple" sense (i.e., bitwise comparison either of all the bits in the structure, or only the "meaningful" bits) this would be anywhere near "quite useful". If you want abstract data types, you know where to find them....
diamond@csl.sony.JUNET (Norman Diamond) (07/20/89)
In article <1989Jul18.020424.2392@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: >Equality comparison on polar representation requires range reduction on >the angle first. This leads again to the need for C++, where you can >define the comparison operation to be arbitrarily complex. Well, with ordinary integers, overflow might occur. Does this mean that "+" should not be provided for integers? -- -- Norman Diamond, Sony Computer Science Lab (diamond%csl.sony.jp@relay.cs.net) The above opinions are inherited by your machine's init process (pid 1), after being disowned and orphaned. However, if you see this at Waterloo or Anterior, then their administrators must have approved of these opinions.
bbadger@x102c.harris-atd.com (Badger BA 64810) (07/20/89)
In article <2261@auspex.auspex.com> you write: >>Sure, you _may_ run into special cases, but is this any reason to leave out >>a useful operation? > >Well, it depends on how useful it *really* is; given enough "special >cases", it may be that the only cases where it *is* useful are special >cases, in which case you can whip up a macro to do the comparison. > >>Other languages, such as Ada (Oh no! The A-word!), provide for comparison >>of composite objects (records in Ada correspond to structs in C). > >So how does Ada define comparison of records? From ANSI/MIL-STD-1815A 22 JAN 1983, which is sometimes called the Ada Language Reference Manual (ALRM), section 4.5.2: \begin{quote} [par 1] The equality and inequality operators are predefined for any type that is not limited. ... [par 5] For two array values or two record values of the same type, the left operand is equal to the right operand if and only if for each component of the left operand there is a {\em matching component} of the right operand, and vice versa; and the values of the matching components are equal, as given in the predefined equality operator for the component type. In particular, two null arrays of the same type are always equal; two null records of the same type are always equal. [par 6] For comparing two records of the same type, {\em matching components} are those which have the same component identifier. \end{quote} > >>Of course there should be caveats about padding data being compared. > >I.e., "padding data gets compared"? That doesn't sound like all that >useful an operation to me; in order to be useful, I'd have to zero out >structures on e.g. the stack. > Right, the component-by-component comparison is much safer, and is the natural approach for Ada. Given C's low-level approach, though, I did not want to rule out from discussion a simplistic compare-all-bytes implementation. That's also why I pointed out some gotcha's. >>Also unions should only be compared to another union or object >>which is *actually using* the same representation. (That is, given: >> union lf_t {long l; float f} lf_a, lf_b; >> lf_a.l = 10; >> lf_b.f = 10.0; >>we should probably not be testing (lf_a == lf_b), but rather >>(lf_a.l == (long) lf_b.f).) > >Fine, so how is the compiler to know to do that? C unions are not >discriminated unions; there's nothing in the union itself to indicate >which member is being used. > >>However, the fact remains that either simple ``compare all bytes'' or >>an expansion to compare all struct members recursively, would be a simple >>extension which could be quite useful. > >Simple "compare all bytes" is certainly simple; how useful it is is >another question, given that comparing padding bytes is simply wrong, >unless you *guarantee* that they're always going to have some "standard" >value that gets in the way. You still haven't indicated how unions are >to be compared, so an expansion to compare all struct members >recursively would fail if any such members were unions. And, once >again, I'll point out that pointer comparison may or may not be what you >want, either. > Yes, comparison of unions is not well-defined, so comparison of structs containing union members would also be not well-defined. >In other words, comparison might be "simple" in a restricted sense, but >nobody's proven that in that "simple" sense (i.e., bitwise comparison >either of all the bits in the structure, or only the "meaningful" bits) >this would be anywhere near "quite useful". > This goes a bit too far, because you throw out the useful comparisons with the ill-defined ones. It is perfectly well-defined and quite handy to define a simple member-by-member comparison on structs and arrays. The only thing you give up are the unions. Comparison of pointers is defined to be comparison of the pointers themselves, just as always. char *p, *q; char a[] = "aa"; char b[] = "bb"; main(){ p = &a[0];q = &b[0]; strcpy(p,"hi"); strcpy(q,"hi"); if (p == p) {printf("Not in C you don't!\n");} else printf("I thought that's what you meant!\n"); } Now, I think that given: typedef struct _pt_t { int x,y,x; } pt_t, * pt_pt; typedef struct _pt_t polyline_t[3]; pt_t p = { 11, 12, 13}; pt_t q = {21, 22, 23}; polyline_t pl = {{ 11, 12, 13}, { 21, 22, 23}, { 31, 32, 33}}; It would be nice to check things like: if ( pl[0] == p ) {} rather than if ( pl[0].x == p. && pl[0].y == p.y && pl[0].z == p.z ) {} >If you want abstract data types, you know where to find them.... Well, this doesn't really have anything to do with abstraction, we're not hiding any implementation. This is just structured data. I wouldn't cry either if a tagged-union record were added to C. That would give the compiler a chance to do the union comparisons too, based on the tags. Bernard A. Badger Jr. 407/984-6385 |``Use the Source, Luke!'' Secure Computer Products |``Get a LIFE!'' -- J.H. Conway Harris GISD, Melbourne, FL 32902 |Buddy, can you paradigm? Internet: bbadger%x102c@trantor.harris-atd.com|'s/./&&/g' Tom sed expansively.
roelof@idca.tds.PHILIPS.nl (R. Vuurboom) (07/21/89)
In article <2261@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes: > >Well, it depends on how useful it *really* is; given enough "special >cases", it may be that the only cases where it *is* useful are special >cases, in which case you can whip up a macro to do the comparison. Whipping, as is well known, is unpleasant at best (but may depend on which side of the whip you're on :-) >>However, the fact remains that either simple ``compare all bytes'' or >>an expansion to compare all struct members recursively, would be a simple ^^^^^^ >>extension which could be quite useful. > >Simple "compare all bytes" is certainly simple; how useful it is is >another question, given that comparing padding bytes is simply wrong, >unless you *guarantee* that they're always going to have some "standard" >value that gets in the way. Agree. >You still haven't indicated how unions are ^^^^^^ >to be compared, so an expansion to compare all struct members >recursively would fail if any such members were unions. Don't we all love to point out the obvious: a struct is not a union and a union is not a struct and never the twain shall meet. To repeat a struct comparison definition I posted a few days back: Now _if_ I were to define struct comparison it would _only_ be for structs for which each member can be directly compared or is a struct to which this requirement is recursively applied. This (and the above) definition is strictly Thatcherite: _no_ unions. With this definition we've got the corollary that two structs compare equal if and only if their members compare equal. So I disallow struct comparisons with structs which have unions, arrays and bitfields as members and possibly some other cases which I can't think of but others undoubtedly can. But my point is that I've still got an awful lot of structs *which occur in the real world* for which I can (and several times wished I could) do a sensible comparison. Looking at the arguments up to now that have been advanced against struct comparison: 1. unions, bit fields (and the related case of data padding) Agreed. But my argument above is that if I exclude these cases I've still got a very relevant operation. 2. member arrays, strings. Why demand direct language support for comparison of arrays/strings in a struct if you don't do it directly? Again exclude this case: I've still got a useful, relevant comparison operator. 3. polar complex example It took a while before I began to get the sneaky feeling that maybe Henry Spencer had put one over me here. His argument was that because a certain _mathematical_ concept (complex comparison) couldn't be supported this was (one of the) grounds for omitting a _language_ concept (struct comparison). This argument holds in my opinion as much water as defining the concept angle as: typedef int angle; Stating that angles modulo 360 are really equal and then stating that since angle1 and angle2 don't compare equal (even when separated by 360 degrees) somethings wrong with the (int) comparison operation (and perhaps should be omitted :-). 4. Language Extension (I've changed my mind on this one). It extends the language but not (much) more than say returning a struct does and less in my opinion than function prototyping for example. 5. The comparison is not simple. Agreed if you want to be able to compare all possible structs. Disagree if you restrict to the above definition. In that case, struct comparison is relatively easily to implement, it certainly is easy to comprehend and it most certainly is a relevant, useful operation even with the stated restrictions. >If you want abstract data types, you know where to find them.... Sure but all I want is a simple struct comparison :-) -- Its a thin red line (and spelling error) between boring and borish. Roelof Vuurboom SSP/V3 Philips TDS Apeldoorn, The Netherlands +31 55 432226 domain: roelof@idca.tds.philips.nl uucp: ...!mcvax!philapd!roelof
gwyn@smoke.BRL.MIL (Doug Gwyn) (07/21/89)
In article <2261@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes: >Simple "compare all bytes" is certainly simple; how useful it is is >another question, given that comparing padding bytes is simply wrong, >unless you *guarantee* that they're always going to have some "standard" >value that gets in the way. Comparing padding is wrong anyway. Even if you could arrange for it to "contain" some standard value (and I'm not sure how you could do that in standards language), there is no constraint so far that says that value must still be there later. The obvious definition of struct comparison would be: structs compare equal if and only if all their corresponding members compare equal. I assure you that it was considered as one of the zillion proposed C language extensions received by X3, but its benefits were not shown to outweigh its drawbacks.
guy@auspex.auspex.com (Guy Harris) (07/22/89)
>Right, the component-by-component comparison is much safer, and is the >natural approach for Ada. Given C's low-level approach, though, I did >not want to rule out from discussion a simplistic compare-all-bytes >implementation. *I'd* rule it out, because it can give the wrong answer, but if you don't care about getting the right answer, or know that in some particular case it will never give the wrong answer, and you *really* want a simplistic compare-all-bytes implementation, you can use "memcpy" - which may be inlined in some implementations. If you want a component-by-component comparison, you can write it yourself, obviously, or wrap it in a macro if you use it a lot. Perhaps not as convenient as having the compiler do it for you, but I'd find it more convenient than, for every structure, deciding whether a compiler notion of structure comparison would really do what I wanted (e.g., the question of "do you compare pointer values or do you compare the values to which they point), or would even work at all (e.g., a structure with unions).
guy@auspex.auspex.com (Guy Harris) (07/22/89)
>1. unions, bit fields (and the related case of data padding) > >Agreed. But my argument above is that if I exclude these cases I've >still got a very relevant operation. I've seen no indication that it's sufficiently relevant *that it should be added to the language*; any definition of structure comparison would be peppered with caveats like "no unions" and "no arrays" and "it compares pointer values, not what they point to" and the like. Yes, there have been cases I've seen where it might have been convenient, but I really *can* live with doing the member-by-member comparison myself. And, given that there's no prior art, I agree with X3J11's decision to leave it out. If somebody sticks it into their compiler as an extension and we can really find out from experience whether enough people actually *would* use it enough to justify its existence, then it can be considered as an extension if it actually is used enough and doesn't confuse people. >3. polar complex example > >It took a while before I began to get the sneaky feeling that maybe >Henry Spencer had put one over me here. > >His argument was that because a certain _mathematical_ concept (complex >comparison) couldn't be supported this was (one of the) grounds for >omitting a _language_ concept (struct comparison). I think Henry's point, like mine, is that the total number of cases where somebody, in effect, defines an equality operator over some data type seems likely to be much larger than the number of cases where this operator is just a member-by-member comparison; complex numbers represented in polar form are one example. Given that, I'd like to see some real-world experience with such a feature before seeing it blessed in a standard.... The original poster *did*, in fact, effectively ask "why isn't structure comparison in ANSI C"? The question was answered, by Henry and others, and I have yet to see a *single* response to that answer that, to me, would justify the inclusion of such a feature *in the ANSI C standard*, given the lack of prior art (and yes, there *was* prior art for function prototypes, namely in C++; it may not have been in an otherwise "pure" C implementation, but at least it existed). I suspect *I* wouldn't use structure comparison if it were available to me in C; I'm almost certain I wouldn't use it if it were available to me in C++ - I'd define an "=" operator for the data type, instead, and not be forced to rely on member-by-member comparison being the right answer.
mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) (07/22/89)
Can I point out something that I haven't seen mentioned here yet? It's called "maintenance." Consider the current situation. If you've got a structure that you need to do comparison ons, and are thinking, you'll have an include file with the structure & a comparison macro for that structure. When you change the structure - in any way - you have the macro in the same place, and can change it right there as apropos for the addition. Now, assume you're using the hypothetical "struct comparison", you don't have a macro - just the structure definition. If you change the structure, you may not think about changing the equality test (no macro nearby to remind you). When you do change it, you have to verify that the default comparison is still legal and correct. If you need to write a macro, you'll have to find every place that comparison is used, and fix it. If the comparison is illegal, this isn't hard, just tedious. If it's legal, it could be a pain. While not something that would make you want to toss the facility completely, it's yet another argument against it. The feature seems to die the death of a thousand cuts. BTW, my standard answer to people who _insist_ that C ought to have a feature is: Get a copy of GNU C, and add that feature. Then, when they do the next revision of the standard, you'll have "prior practice" for the committe. This is a lot more likely to get it added than arguing about it on USEnet. Besides which, you'll be able to write non-conforming code that uses that feature in the meantime. <mike -- I went down to the hiring fair, Mike Meyer For to sell my labor. mwm@berkeley.edu I noticed a maid in the very next row, ucbvax!mwm I hoped she'd be my neighbor. mwm@ucbjade.BITNET
peter@ficc.uu.net (Peter da Silva) (07/24/89)
In article <2266@auspex.auspex.com>, guy@auspex.auspex.com (Guy Harris) writes: > notion of structure comparison would really do what I wanted (e.g., the > question of "do you compare pointer values or do you compare the values > to which they point), You compare pointer values. > or would even work at all (e.g., a structure with > unions). This should be illegal (as should initialising a union). -- Peter da Silva, Xenix Support, Ferranti International Controls Corporation. Business: peter@ficc.uu.net, +1 713 274 5180. | "...helping make the world Personal: peter@sugar.hackercorp.com. `-_-' | a quote-free zone..." Quote: Have you hugged your wolf today? 'U` | -- hjm@cernvax.cern.ch
roelof@idca.tds.PHILIPS.nl (R. Vuurboom) (07/25/89)
In article <2267@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes: | |I've seen no indication that it's sufficiently relevant *that it should |be added to the language*; any definition of structure comparison would |be peppered with caveats like "no unions" and "no arrays" and "it |compares pointer values, not what they point to" and the like. | Ok, let me try and put my money where my mouth is: Structure comparison is defined for structures which are recursively derived from basic, enumerated, pointer or structure types. Two structs of the same derived type for which structure comparison is defined compare equal if and only if each member (recursively) compares equal. Which points out that in order to define something you don't necessarily need to state what it isn't but just what it is. |Yes, there have been cases I've seen where it might have been |convenient, but I really *can* live with doing the member-by-member |comparison myself. Agreed, so can I. I can live without struct assignment too but I kind of like having it. I don't think the "living without" argument is really fair. We can all live without a lot of things (probably even C :-). |And, given that there's no prior art, I agree with |X3J11's decision to leave it out. Which makes me start wondering about volatile or - to go to another extreme - const. |If somebody sticks it into their |compiler as an extension and we can really find out from experience |whether enough people actually *would* use it enough to justify its |existence, then it can be considered as an extension if it actually is |used enough and doesn't confuse people. | The above I consider valid arguments, translating: Is it relevant? viz. can you expect it to be used in "mainstream" programming? Is it straightforward? Perhaps to put it another way: is it "natural". |The original poster *did*, in fact, effectively ask "why isn't structure |comparison in ANSI C"? The question was answered, by Henry and others, |and I have yet to see a *single* response to that answer that, to me, |would justify the inclusion of such a feature *in the ANSI C standard*, |given the lack of prior art (and yes, there *was* prior art for function |prototypes, namely in C++; it may not have been in an otherwise "pure" C |implementation, but at least it existed). Obviously I can't be sure that any particular argument will convince you but this one might convince me: enum make_t {BMW,PEUGEOUT,RENAULT,MERCEDES,... enum colour_t {CHROMIUM_RED,CANARY_YELLOW, typedef car { make_t make; colour_t colour; } ... for( i=0; i < nr_cars_in_stock; i++ ) { .. if ( car_wanted == cars_in_stock[i] ) ... |I suspect *I* wouldn't use |structure comparison if it were available to me in C; I'm almost certain |I wouldn't use it if it were available to me in C++ - I'd define an "=" |operator for the data type, instead, and not be forced to rely on |member-by-member comparison being the right answer. The choice of whether you would want (need) to use abstract data typing or data structure comparison is really quite clear cut. It is the cut between whether the data structure represents an abstraction (complex numbers case in point) or represents a combinatoric. In the first case the object is _more_ than the sum of its parts. In the second case the object _is_ the sum of its parts. A complex number has "more" meaning than a pair of reals hence the extra operations needed to bring out this meaning. A red car does not represent a higher abstraction level than the concepts red and car considered separately. To put it simply, all applications that use combinatoric objects (in the sense I've defined) could (and I think would) use struct comparison. In this particular application area struct comparison is both relevant and straightforward. Attempting to quantify how often this comes up and how often it needs to come up to make into X3J11 is something I find impossible to do. All I can say is that I have come across the above application area a number of times. -- I don't know what the question means, but the answer is yes... (overheard on comp.lang.misc) Roelof Vuurboom SSP/V3 Philips TDS Apeldoorn, The Netherlands +31 55 432226 domain: roelof@idca.tds.philips.nl uucp: ...!mcvax!philapd!roelof
guy@auspex.auspex.com (Guy Harris) (07/25/89)
>> notion of structure comparison would really do what I wanted (e.g., the >> question of "do you compare pointer values or do you compare the values >> to which they point), > >You compare pointer values. Which may not always correspond to what you want; i.e., "these two structure values have the same values in all their fields" may not be equivalent to "the objects these structures represent are equal". If, say, experience with Ada indicates that they are frequently equivalent, and that people do use structure comparison heavily, that experience might, with some care, be applicable to C; otherwise, the right thing to do is NOT to put it into the standard, but put it into GCC or some other compiler and see how often it's really used.
bbadger@x102c.harris-atd.com (Badger BA 64810) (07/25/89)
In article <2267@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes: [..stuff deleted...] >I've seen no indication that it's sufficiently relevant *that it should >be added to the language*; any definition of structure comparison would >be peppered with caveats like "no unions" and "no arrays" and "it >compares pointer values, not what they point to" and the like. When I entered this discussion, it was centering on whether struct comparison was a well-defined and useful operation. I think that has been established for structs not containing unions. Whether to add it to the language -- in particular whether to include it in ANSI C -- is another, more (mostly?) political question. > >Yes, there have been cases I've seen where it might have been >convenient, but I really *can* live with doing the member-by-member >comparison myself. And, given that there's no prior art, I agree with >X3J11's decision to leave it out. If somebody sticks it into their >compiler as an extension and we can really find out from experience >whether enough people actually *would* use it enough to justify its >existence, then it can be considered as an extension if it actually is >used enough and doesn't confuse people. There may be ``no prior art'' with standard C, but let's not ignore prior art from other programming languages. Struct comparison is less confusing than unions and bit fields. Anyway, Real Programmers (TM) like Guy probably aren't using struct assignment and function return values either (:-). >>3. polar complex example >> >>It took a while before I began to get the sneaky feeling that maybe >>Henry Spencer had put one over me here. >> >>His argument was that because a certain _mathematical_ concept (complex >>comparison) couldn't be supported this was (one of the) grounds for >>omitting a _language_ concept (struct comparison). > >I think Henry's point, like mine, is that the total number of cases >where somebody, in effect, defines an equality operator over some data >type seems likely to be much larger than the number of cases where this >operator is just a member-by-member comparison; complex numbers >represented in polar form are one example. Given that, I'd like to see >some real-world experience with such a feature before seeing it blessed >in a standard.... > >The original poster *did*, in fact, effectively ask "why isn't structure >comparison in ANSI C"? The question was answered, by Henry and others, >and I have yet to see a *single* response to that answer that, to me, >would justify the inclusion of such a feature *in the ANSI C standard*, >given the lack of prior art (and yes, there *was* prior art for function >prototypes, namely in C++; it may not have been in an otherwise "pure" C >implementation, but at least it existed). I suspect *I* wouldn't use >structure comparison if it were available to me in C; I'm almost certain >I wouldn't use it if it were available to me in C++ - I'd define an "=" >operator for the data type, instead, and not be forced to rely on >member-by-member comparison being the right answer. Of course, you wouldn't be *forced* to rely on member-by-member comparison! You could still write your own function, or more likely macro. Careful programmers would probably do that anyway, to maintain the abstraction. However, wouldn't it be nice if you *could* write #define COMPLEX_EQUAL(a,b) ((a) == (b)) instead of #define COMPLEX_EQUAL(a,b) ((a).real == (b).real && (a).imag == (b).imag) (Whew! That was a really tough one!) What if we define: typedef struct _vector_t {int x,y,z;} vector_t; typedef struct _matrix_t {vector_t x,y,z;} matrix_t; static const matrix_t identity_matrix = {{1,0,0},{0,1,0},{0,0,1}}; static matrix_t m1 = {{1,0,0},{0,0,1},{0,1,0}}; It may be convenient to inquire: { int flag = m1 == identity_matrix; ....} Isn't it good? I'll quote from ``C: A Reference Manual'' by Harbison and Steele, p 106: 5.7.1 Operations on Structures ... It is not permitted to compare two structures for equality. An object of a structure type is a sequence of components of other types. Because certain data objects may be constraind by the target computer to lie on certain addressing boundaries, a structure object may contain ``holes,'' storage units that do not belong to any component of the structure. The holes would make equality tests implemented as a wholesale bit-by-bit comparison unreliable, and component-by-component equality tests would be too expensive. (Of course, the programmer may write component-by-component equality functions.) I don't find this persuasive. If an equality test is required, the programmer is going program it anyway. The problems performing the test don't go away just because the compiler has passed the responsibility to the programmer. Perhaps the compiler will be able to produce better code than the average programmer. If not, (and I'm repeating myself here,) a programmer can usually avoid any language feature he doesn't like and do it the old-fashioned way. I don't know much about the politics and practicalities of introducing concepts to the current ANSI C. I've heard that the purpose is more to standardize existing practice than to correct deficiencies that aren't outright faults. So be it. I'm posting more in the hope of rescuing this simple idea from the criticisms by Guy and others that struct comparison is complex, ill-defined or not useful. Bernard A. Badger Jr. 407/984-6385 |``Use the Source, Luke!'' Secure Computer Products |``Get a LIFE!'' -- J.H. Conway Harris GISD, Melbourne, FL 32902 |Buddy, can you paradigm? Internet: bbadger%x102c@trantor.harris-atd.com|'s/./&&/g' Tom sed expansively.
jeffrey@algor2.uu.net (Jeffrey Kegler) (07/25/89)
In article <2280@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes: >>You compare pointer values. > >Which may not always correspond to what you want; i.e., "these two >structure values have the same values in all their fields" may not be >equivalent to "the objects these structures represent are equal". If, >say, experience with Ada indicates that they are frequently equivalent, >and that people do use structure comparison heavily, that experience >might, with some care, be applicable to C; otherwise, the right thing to >do is NOT to put it into the standard, but put it into GCC or some other >compiler and see how often it's really used. Precisely right. If we were arbitrarily stuck with an untested interpretation of structure comparison, we might soon regret it. I have my guess as the best way to compare structures by default (ignore unions and padding, compare pointers by value), but any guess that winds up in the standard we would be stuck with for a long time to come. The proper way to lobby for your favorite method of structure comparison is to hack GCC, and submit it to a jury of our peers. Just sticking a best guess into a standard is not a good idea. The ANSI C Committee deserves congratulations for having recognized this. -- Jeffrey Kegler, President, Algorists, jeffrey@algor2.UU.NET or uunet!algor2!jeffrey 1762 Wainwright DR, Reston VA 22090
ray@philmtl.philips.ca (Raymond Dunn) (07/26/89)
In article <2280@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes: >.........If, >say, experience with Ada indicates that they are frequently equivalent, >and that people do use structure comparison heavily, that experience >might, with some care, be applicable to C I'm glad Ada has been mentioned, because that language demonstrates clearly the problems when all things for all men are added to a language. 'C' adequately provides the basic tools you need to build your own pet version of struct comparison, as well as most of the other things on your particular wish-list. 'C' is already starting to suffer from committee-itis and library-itis. Keep it lean... keep it lean!!! -- Ray Dunn. | UUCP: ..!uunet!philmtl!ray Philips Electronics Ltd. | TEL : (514) 744-8200 Ext: 2347 600 Dr Frederik Philips Blvd | FAX : (514) 744-6455 St Laurent. Quebec. H4M 2S9 | TLX : 05-824090
guy@auspex.auspex.com (Guy Harris) (07/26/89)
>If ANSI C had permitted even a strongly constrained comparable struct type >these problems would have been eliminated. (E.g. add "comparable" struct >to the language: OK, what if I want to see if one file offset is larger than, or smaller than, another? It may be uncommon, or it may not - until somebody's scoured a large body of code, I'd assume there is code that does comparisons on file offsets, since it is permissible on integral types.... >compilers would be permitted to reorder to allow comparison as a >byte-by-byte comparison; Reorder structure members? I think that's a separate issue.... >Even off_t would have been helped, as only the add and subtract operators >would have to be macros were this possible. Those are not _too_ >common. Perhaps add and subtract aren't as common as other operators, but I'd still be a bit annoyed if I couldn't add and subtract file offsets; unlike structure comparison, I've used addition of file offsets on a number of occasions. >(Something has to give with off_t, and soon; 4Gb disks are coming along >very soon. It would be nice to find a way to deal with them without >having to rewrite every use of off_t and lseek() in the world. Me, I'd vote for "long long int", which I doubt would be "otherwise unneeded" - Convex, at least, thought they needed it. As an integral type, it should require less rewriting (although there is the problem that existing systems define "off_t" otherwise - but that problem exists with other proposed changes to "off_t" as well).
guy@auspex.auspex.com (Guy Harris) (07/26/89)
>Just like the compiler doesn't have enough information to >initialize a union, right? ! > >A simple rule like comparing first members of unions and the >pointers themselves would work nicely in a lot of cases and >match the way initialization works. Uh, as far as I'm concerned, the "first member" rule's only use is to give a meaning to the default initialization of unions. It means I can't initialize, say, an array of union types or objects containing union types if different elements of that array have different union members "active", for example (e.g., a symbol table, with symbols having, say, string, integral, or floating-point values, selected by a discriminator - if I want the initial symbol table to have values of more than one type, I lose). Had it not been for the necessity of giving *some* meaning to initialization of unions, I'd just as soon have left initialization of them undefined....
nevin1@cbnewsc.ATT.COM (nevin.j.liber) (07/28/89)
In article <2410@trantor.harris-atd.com> bbadger@x102c.harris-atd.com (Badger BA 64810) writes: >When I entered this discussion, it was centering on whether struct comparison >was a well-defined and useful operation. I think that has been established >for structs not containing unions. Whether to add it to the language -- >in particular whether to include it in ANSI C -- is another, more >(mostly?) political question. It is NOT mostly a political question! There are problems that would be introduced with it! Consider the following scenario: Jane Programmer, fresh out of college, reads all about C with the struct equality extension (C-SEE :-)), and is raring to go program with it. She, along with her colleages, write 10,000,000 lines of code in C-SEE. An example of a struct used in this code (and there are thousands) is: struct typical { int foo; /* ... hundreds of variables */ char bar; } Three years later, you come on the scene. Your boss asks you to make some enhancements to the ten million line program, and one of them requires you to change struct typical (among other things). Now it looks like: struct typical { int foo; /* ... hundreds of variables */ char bar; short uh_oh; } Guess what happens? The code breaks!! By seemingly innocently adding a field to the struct, you now have to go through and fix all the code you broke. If you are lucky, and you remembered to do this before you sent the code to the testers, you could get the compiler to find all the instances of the struct (by simply adding a union to the struct typical definition, and having the compiler give you the error lines), but that isn't the point. Also, how do you plan on fixing the code? Are you going to think about each and every struct comparison, and decide on-the-spot whether or not the rewrite it the way you would in standard C (if a union was added to typical, you would *have* to rewrite ALL the C-SEE dependent stuff)? The only situation where the C-SEE extension would be useful is when you know that you just want to compare all the elements of the struct together. In order to do this, you can't abstract over the struct; you have to *know* what each element is in order to use C-SEE safely. It is better self-documentation, as well as safer, to just write out the member comparisions longhand. -- NEVIN ":-)" LIBER AT&T Bell Laboratories nevin1@ihlpb.ATT.COM (312) 979-4751
guy@auspex.auspex.com (Guy Harris) (07/29/89)
... > char bar; > short uh_oh; > } > >Guess what happens? The code breaks!! By seemingly innocently adding >a field to the struct, you now have to go through and fix all the code >you broke. Are you implying here that: 1) "uh_oh" isn't supposed to be compared when you do structure comparisons or 2) C-SEE compiles all structure comparisons into comparisons of all the bytes of the structure? If 2), I think it's been established that the *only* correct definition of structure comparison would be member-by-member, and if that means the structure comparison doesn't compile into e.g. a single "CMPCn" instruction on a VAX, too bad. While this may surprise some users of the structure comparison construct (and, if it surprises a lot of them, it means advocates of structure comparison had better be prepared to educate said users), it means that adding a structure member that causes padding to be added to a structure won't break structure comparisons.
peter@ficc.uu.net (Peter da Silva) (07/29/89)
In article <2092@cbnewsc.ATT.COM>, nevin1@cbnewsc.ATT.COM (nevin.j.liber) writes: > Guess what happens? The code breaks!! Why? > It is better self-documentation, as well as safer, to just write out the > member comparisions longhand. And how many times do you forget one? -- Peter da Silva, Xenix Support, Ferranti International Controls Corporation. Business: peter@ficc.uu.net, +1 713 274 5180. | "...helping make the world Personal: peter@sugar.hackercorp.com. `-_-' | a quote-free zone..." Quote: Have you hugged your wolf today? 'U` | -- hjm@cernvax.cern.ch
mcdaniel@uicsrd.csrd.uiuc.edu (Tim McDaniel) (07/29/89)
In article <2288@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes: >OK, what if I want to see if one file offset is larger than, or smaller >than, another? ... >Perhaps add and subtract aren't as common as other operators, but I'd >still be a bit annoyed if I couldn't add and subtract file offsets; >unlike structure comparison, I've used addition of file offsets on a >number of occasions. The BSD 4.3 man page for fseek(3S) and ftell(3S) says: _Ftell_ returns the current value of the offset relative to the beginning of the file associated with the named _stream_. It is measured in bytes on UNIX; on some other systems it is a magic cookie, and the only foolproof way to obtain an _offset_ for _fseek_. K&R 2, 1st edition, p. 248, says (for fseek): For a binary file, the position is set to _offset_ characters from _origin_, which may be SEEK_SET (beginning), SEEK_CUR (current postion), or SEEK_END (end of file). For a text stream, _offset_ must be zero, or a value returned by _ftell_ (in which case _origin_ must be SEEK_SET). Thus, in pANS C, a *text* stream offset may indeed be a "magic cookie", for which comparison and arithmetic is undefined. Binary mode requires an actual character number. (Personally, I see no point in having the distinction; I'd like to see all _offset_s be magic cookies. It's too late, now that X3J11 has acted.) -- "Let me control a planet's oxygen supply, and I don't care who makes the laws." - GREAT CTHUHLU'S STARRY WISDOM BAND (via Roger Leroux) __ \ Tim, the Bizarre and Oddly-Dressed Enchanter \ mcdaniel@uicsrd.csrd.uiuc.edu /\ mcdaniel%uicsrd@{uxc.cso.uiuc.edu,uiuc.csnet} _/ \_ {uunet,convex,pur-ee}!uiucuxc!uicsrd!mcdaniel
guy@auspex.auspex.com (Guy Harris) (07/30/89)
>The BSD 4.3 man page for fseek(3S) and ftell(3S) says:
Which is irrelevant, since the original poster was talking about, among
other things, "off_t" from POSIX, which *is* an integral type, and POSIX
file offsets, which *are* measured in bytes. The fact that, in ANSI C,
you can get away with "fseek()" offsets not being integral types isn't
relevant; in POSIX, they'd better be integral types, and absent
something like "long long int", which isn't in strict ANSI C, the best
you can do is "long", which in many implementations is, for better or
worse, 32 bits.
mmengel@cuuxb.ATT.COM (Marc W. Mengel) (08/03/89)
In article <2289@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes: >>Just like the compiler doesn't have enough information to >>initialize a union, right? ! >Uh, as far as I'm concerned, the "first member" rule's only use is to >give a meaning to the default initialization of unions. It means I >can't initialize, say, an array of union types or objects containing >union types if different elements of that array have different union >members "active"... Why can't we adopt a simple rule like initializing the first union member of the right type? something like union { char c; int i; float f;} bozo[3]={ (int)5, (char)5,(float)5}; would make it clear which union member is being initialized; if there are two union members of the same type it doesnt matter which one of the two you initialize. For more complicated types (unions of structures, etc.) you would have to recursively check the types of members to find a match, but you already have to do the recursive checks to match curly braces to sub-structures or arrays are in the right place, so... >Had it not been for the necessity of giving *some* meaning to >initialization of unions, I'd just as soon have left initialization of >them undefined.... -- Marc Mengel mmengel@cuuxb.att.com attmail!mmengel ...!{lll-crg|att}!cuuxb!mmengel