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-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,f71c159449d6e114 X-Google-Attributes: gid103376,public From: mheaney@ni.net (Matthew Heaney) Subject: Re: Ada 83 - avoiding unchecked conversions. Date: 1996/12/11 Message-ID: X-Deja-AN: 203630078 references: <32AED68A.48BE@aisf.com> content-type: text/plain; charset=ISO-8859-1 organization: Estormza Software mime-version: 1.0 newsgroups: comp.lang.ada Date: 1996-12-11T00:00:00+00:00 List-Id: In article <32AED68A.48BE@aisf.com>, "Chris Sparks (Mr. Ada)" wrote: >> function To_Integer_32 (Low, High : Integer_16) >> return Integer_32 is >> >> type Integer_32_Record is >> record >> High_Order : Integer_16; >> Low_Order : Integer_16; >> end record; >> >> for Integer_32_Record use >> record >> High_Order at 0 range 16 .. 32; > >You mean 31. > >> Low_Order at 0 range 0 .. 15; > >You have to be careful here due to portability and bit ordering. Someone else also pointed that out to me. Does anyone know how to use the Bit_Order attribute to make this portable? Is this acceptable: for Integer_32_Record'Bit_Order use System.Low_Bit_First; I'm confused because I'm not sure whether storage unit 0 refers to the most significant bit or the least significant. Does the Bit_Order attribute only affect the interpretation of the bits, or of the storage unit too? > The_Record_Address : constant System.Address := The_Record'Address; > Result : Integer_32; > for Result'Address use The_Record_Address; -- New way >--for Result use at The_Record_Address; -- Old way I disagree with this "solution." Overlays are never the way to go when Unchecked_Conversion will do. >> Some shops have the rule "Thou shalt not use Unchecked_Conversion." >> But this is silly; use it when it makes sense. > >I concur. Using Address Clauses would not be the right choice when >a component within a structure has an initializing value (pointers, >explicit initializations). Yes, that it true, but it's still not the right solution here. Unchecked_Conversion is. >> The proper place to use Unchecked_Conversion is at the interface >> boundary of the sytem. That seems to be the case for you, because you're >> manipulating types whose size is known explicitly (16 and 32 bit integers). > >I don't know what this means. "Close-to-metal" programming. Think of a program as a system with definate boundaries. The boundaries for an embedded system, say, are the computer itself (the OS or kernal, etc) and hardware devices over which you perform external I/O. When you do external device I/O, you have to know explicitly what the size and representation is of all the data you exchange with the other processor, because you both have to agree on a common format. Ada excels in this area because it allows you to state explicitly what the representation of the data is by using size clauses and representation clauses. But knowing the representation of the data is only important at the hardware level, ie "the interface boundary." Internal to the software there's a lot going on that doesn't depend on representation of the data, so we want to practice some information hiding by letting the compiler choose the representation. For example, type T is range 1 .. 10; I can use type T to do some calculations, but I certainly don't care if T occupies 8, 16, or 32 bits. It's a perfectly valid request to not use Unchecked_Conversion on types like T, because I'm inside the software system. But at the I/O layer, I can't use types like T because I really do need to know T's representation (because I have to send it to someone else outside the system). So yes, I often really do need to use Unchecked_Conversion - at the interface boundary. Shops that make rules like "Don't use Unchecked_Conversion" mean well but are confusing the internal and external aspects of the (software) system. This confusion is also the reason why shops often say "Thou shalt not use predefined types, because it's not portable." This too is another silly rule. It would be perfectly valid for such a rule at the interface layer, because I have to know the representation of my types. But internal to the software system, I don't care, and using predefined types is just another form of information hiding. I've often seen code like this type Stack is limited private; type Length_Type is range ... for Lenght_Type'Size use 32; function Length (S : Stack) return Length_Type; ... private type Stack is ...; end; This is pure overkill: who cares what the representation of the stack length attribute is? It's also wrong because they didn't use a representation clause on the representation of type Stack. Are you going to send the stack object across an interface? If not, then why do you care what the representation is? function Length (S : Stack) return Natural; is a perfectly good use of a predefined type. Another egregious example is with array declarations: type T_Array is array (Integer_32 range <>) of T; This is completely wrong: who cares what the representation of the array index subtype is? You never care about that even at the interface layer, because you don't actually send the array index across the interface - only the components of the array. Which is why using a subtype of Positive is often the best type for an array index subtype. -------------------------------------------------------------------- Matthew Heaney Software Development Consultant mheaney@ni.net (818) 985-1271