macrakis@harvard.ARPA (Stavros Macrakis) (06/18/85)
More Ada misinformation. This is getting dull. In my article <192@harvard.ARPA>, I wrote: > > ...unchecked_conversion, is so simple to implement (you just turn > > off type checking!).... This is the main thing you need to do > > C-like low-level pointer manipulations. Darin Johnson replies: <266@sdcc13> ...say C programmers start to use > Ada.... [what] if they ... [p]ut unchecked_conversion at the start > of all their programs. Then when they wanted to make distributions, > they would remove it.... [and eventually] suggest that untyped_ > conversion should be the default... This is not how Unchecked_conversion works. It is a generic function which can be instantiated to produce a function which converts between any two types bit-to-bit; something like C's casts. So there is no danger of global unchecked conversions. See Appendix for an example (or study Ada before talking about it!). Thus, although it is in principle possible to commit the usual C uglinesses in Ada, the language reminds you (...!) whenever you're slipping into low-think. I was simply refuting the argument `you can't do xxx in Ada', not saying that you ought to do xxx in Ada! -s Appendix How to use unchecked_conversion in Ada -- Suppose the type of the records in a file is determined in the -- file itself. Then you cannot expect to use the standard Ada -- sequential I/O package. Instead, you read into a binary buffer -- and use unchecked_conversion. type rec is ...; subtype bufslice is ...; ... function Buf_to_rec(words: bufslice) return rec is new Unchecked_conversion(bufslice,rec); -- no code generated ... thisrec := Buf_to_rec(Buffer(i..i+rec'size-1)); -- assuming Buffer is an array of storage-units. Alternatively, you can use pointers: ... type recptr is access rec; ... function Bufaddr_to_recptr(adr: address) return recptr is new Unchecked_conversion(address,recptr); -- no code generated ... thisrecptr := Bufaddr_to_recptr(Buffer(i)'address); -- no code generated for conversion nor 'address
guy@sun.uucp (Guy Harris) (06/20/85)
> a function which converts between any two types bit-to-bit; something > like C's casts. C casts are not bit-for-bit conversions unless the conversion happens to be implemented as such. This is the case for signed <-> unsigned conversions on two's complement machines, pointer <-> integer conversions, and pointer <-> pointer conversions in most cases on byte-addressible machines. C compilers don't complain about conversions between pointers of different types, nor do they complain about various other type conversions. "lint" will complain about more of them. I've found bugs in kernel code I've written that would have been found by "lint" (for those of you who think strong type checking is a Bad Thing in system code). Note that the idea of bit-for-bit conversion operators dates back to PL/I's "unspec" (which, like PL/I's pointers, was typeless); Mesa has a bit-for-bit type conversion operator "loophole" similar in concept to Ada's. Guy Harris
macrakis@harvard.ARPA (Stavros Macrakis) (06/21/85)
> > ...converts between...two types bit-to-bit; something like C's casts. > C casts are not bit-for-bit conversions unless the conversion happens > to be implemented as such... I would put it differently: C casts ARE bit-for-bit conversions except sometimes for numerical types. To the extent that one can speak of C having any semantics at all, this makes the semantics of C casts grossly inconsistent. For instance, (int) 2.3 == 2, but (*var=2.3, *((int *) var) ) == garbage; I don't even want to begin to think about the semantics of conversions involving unsigned's. I also don't understand what `happens to be implemented as' means. What other possibilities are there for converting pointers to integers, incompatible pointers, etc.? So perhaps it was a bad idea to compare Unchecked_conversion in Ada to C casts. I just wanted to use a reference point familiar to C users. -s
guy@sun.uucp (Guy Harris) (06/23/85)
> > > ...converts between...two types bit-to-bit; something like C's casts. > > > C casts are not bit-for-bit conversions unless the conversion happens > > to be implemented as such... > > I would put it differently: C casts ARE bit-for-bit conversions except > sometimes for numerical types. "You play Bach your way; I will play him his way." -W. Landowska You can read K&R your way; I'll read it their way. The only mention they make of a conversion being a copy of the bits is under the int-to-unsigned conversion: The value is the least unsigned integer congruent to the signed integer (module 2^wordsize). *In a 2's complement representation*, this conversion is conceptual and there is no actual change in the bit pattern. Maybe they should have left the sentence about 2's complement representation out, so people wouldn't think of it as a bit-for-bit copy. As for pointer-to-integer conversions: A pointer may be converted to any of the integral types large enough to hold it. ... The mapping function is also machine dependent, but is intended to be unsurprising to those who know the addressing structure of the machine. This may be a bit-for-bit copy on most machines, but it need not be. > To the extent that one can speak of C having any semantics at all, this > makes the semantics of C casts grossly inconsistent. For instance, > (int) 2.3 == 2, but (*var=2.3, *((int *) var) ) == garbage; So? Presumably, in other languages (like Ada), if you convert 2.3 to an integer, you get 2, while if you do an (unchecked) conversion of a pointer to a floating-point variable into a pointer to an integer, and then dereference that pointer, you also get an integer with the same bit pattern as the floating-point number in that variable (which isn't "garbage" if you're picking the bits apart). > I don't even want to begin to think about the semantics of conversions > involving unsigned's. Why not? The C rules are mathematically reasonable; what else would you do, aside from generating an exception of the signed quantity is negative. Or is the lack of checking what you object to? I might agree with you on that one, although C doesn't have an exception mechanism (people have debated the merits of general exception mechanisms, so they're not considered a Good Thing by the entire community). > I also don't understand what `happens to be implemented as' means. What > other possibilities are there for converting pointers to integers, > incompatible pointers, etc.? Well, I'm not sure why you have trouble understanding it, but I'll explain; I was referring to the int <-> unsigned conversion, which happens to be implemented that way on 2's complement machines. Pointer-to-pointer conversions aren't necessarily bit-for-bit on word-addressed machines; byte pointers (like "char *") and word-pointers (like all other pointers might be) don't have the same bit pattern (or even the same number of bits) in all implementations. > So perhaps it was a bad idea to compare Unchecked_conversion in Ada to C > casts. I just wanted to use a reference point familiar to C users. A better comparison would point out that C has no formal unchecked conversions, and as such certain conversions which should require the programmer to say "yes, I'm cheating, but I know what I'm doing" don't. If C had such a concept, conversion of pointers to integers, integers to pointers, and pointers to other types of pointers should require that the programmer explicity specify the conversion as unchecked, so that they're at least reminded that they're Doing Something Potentially Nasty. In practice, the portable C compiler does generate warnings for all three of those cases; you can defeat those warnings by doing the cast on the RHS of the assignment instead of by default in the assignment. However: 1) this is a gross hack, since a cast is merely a way to explicitly indicate a coercion - or at least that's what it should be ("An expression preceded by the parenthesized name of a data type causes conversion of the value of the expression to the named type.") "a = b" and "a = (typeof a)b" should be equivalent expressions. 2) warnings can be ignored, so to be truly secure it should give something stronger than a warning. C certainly has its share of things to criticize; however, a large number of them are shared by other popular languages of its general class. Criticism should be accurate and fair; I think the point you really want to make (i.e., that certain conversions in C should not be so cavalierly accepted) can be made in a better way (by saying as much, rather than by dismissing C casts as bit-for-bit copies). Guy Harris