* Interfaces.Shift_Left @ 2011-12-12 22:30 awdorrin 2011-12-12 23:34 ` Interfaces.Shift_Left Simon Wright 2011-12-13 12:00 ` Interfaces.Shift_Left Brian Drummond 0 siblings, 2 replies; 22+ messages in thread From: awdorrin @ 2011-12-12 22:30 UTC (permalink / raw) Perhaps I'm just brain-dead after staring at code all day - but I'm currently stumped and hoping someone could point me in the right direction. I've been trying to update old Ada code to Ada95 standards and wanted to replace the calls to a custom C 'bit' library with the methods available in the Interface package. The interface package only takes unsigned values as parameters, which I figured is fine since at a bit level sign doesn't really matter, but looks like I was wrong, as I'm now encountering a constraint error after a Shift_Left operation's results are casted back to an Integer_32 type. The code is similar to the following: Cur_Word := (Cur_Word OR Shift_Left( Unsigned_32(Data), Bits_To_Shift)); INT_PTR.all := Integer_32(Cur_Word); I understand that the result from the shift_left is a negative number, so it is being seen by Ada as a large positive number ( > (2^31-1)) which is why I'm getting the Constraint error; Maybe its my history with C that is confusing me, but shouldn't there be an easy way to cast the value back to a negative Integer_32 from an Unsigned_32? Thanks! ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-12 22:30 Interfaces.Shift_Left awdorrin @ 2011-12-12 23:34 ` Simon Wright 2011-12-13 1:36 ` Interfaces.Shift_Left Adam Beneschan 2011-12-13 12:00 ` Interfaces.Shift_Left Brian Drummond 1 sibling, 1 reply; 22+ messages in thread From: Simon Wright @ 2011-12-12 23:34 UTC (permalink / raw) awdorrin <awdorrin@gmail.com> writes: > Cur_Word := (Cur_Word OR Shift_Left( Unsigned_32(Data), > Bits_To_Shift)); > INT_PTR.all := Integer_32(Cur_Word); > > I understand that the result from the shift_left is a negative number, > so it is being seen by Ada as a large positive number ( > (2^31-1)) > which is why I'm getting the Constraint error; > > Maybe its my history with C that is confusing me, but shouldn't there > be an easy way to cast the value back to a negative Integer_32 from an > Unsigned_32? Ada doesn't have an easy way to do what you ask; one way you can do it is by instantiating Ada.Unchecked_Conversion, which is deliberately obvious so that reviewers know that they have to take more care than usual. It'd be much easier if Data was Unsigned_32 to start with, and if instead of INT_PTR you had an Unsigned_32_Ptr. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-12 23:34 ` Interfaces.Shift_Left Simon Wright @ 2011-12-13 1:36 ` Adam Beneschan 0 siblings, 0 replies; 22+ messages in thread From: Adam Beneschan @ 2011-12-13 1:36 UTC (permalink / raw) On Dec 12, 3:34 pm, Simon Wright <si...@pushface.org> wrote: > awdorrin <awdor...@gmail.com> writes: > > Cur_Word := (Cur_Word OR Shift_Left( Unsigned_32(Data), > > Bits_To_Shift)); > > INT_PTR.all := Integer_32(Cur_Word); > > > I understand that the result from the shift_left is a negative number, > > so it is being seen by Ada as a large positive number ( > (2^31-1)) > > which is why I'm getting the Constraint error; > > > Maybe its my history with C that is confusing me, but shouldn't there > > be an easy way to cast the value back to a negative Integer_32 from an > > Unsigned_32? > > Ada doesn't have an easy way to do what you ask; one way you can do it > is by instantiating Ada.Unchecked_Conversion, which is deliberately > obvious so that reviewers know that they have to take more care than > usual. In fact, I think most C casts are, in essence, "unchecked conversions". In Ada, however, type conversions (specifically, value conversions) are more strictly defined, and it's defined so that the result of a type conversion has the same *value* as the operand, with allowance for rounding. So the idea of a type conversion whose operand is a positive number and whose result is a negative number is not how Ada does things. -- Adam ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-12 22:30 Interfaces.Shift_Left awdorrin 2011-12-12 23:34 ` Interfaces.Shift_Left Simon Wright @ 2011-12-13 12:00 ` Brian Drummond 2011-12-13 13:15 ` Interfaces.Shift_Left awdorrin 1 sibling, 1 reply; 22+ messages in thread From: Brian Drummond @ 2011-12-13 12:00 UTC (permalink / raw) On Mon, 12 Dec 2011 14:30:51 -0800, awdorrin wrote: > Perhaps I'm just brain-dead after staring at code all day - but I'm > currently stumped and hoping someone could point me in the right > direction. > > I've been trying to update old Ada code to Ada95 standards and wanted to > replace the calls to a custom C 'bit' library with the methods available > in the Interface package. > > The interface package only takes unsigned values as parameters, which I > figured is fine since at a bit level sign doesn't really matter, but > looks like I was wrong, as I'm now encountering a constraint error after > a Shift_Left operation's results are casted back to an Integer_32 type. Is there any way you could use modular types instead? They are closer to the semantics of C unsigned. - Brian ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-13 12:00 ` Interfaces.Shift_Left Brian Drummond @ 2011-12-13 13:15 ` awdorrin 2011-12-13 21:48 ` Interfaces.Shift_Left Randy Brukardt 0 siblings, 1 reply; 22+ messages in thread From: awdorrin @ 2011-12-13 13:15 UTC (permalink / raw) The data being manipulated does start out as signed 32-bit integers - its the Logical Shift operations in the Interfaces package that are expecting Unsigned_32 types as input parameters. After a good night's sleep - the Unchecked_Conversion seems like the best choice here, if I want to stick with using the Interfaces package. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-13 13:15 ` Interfaces.Shift_Left awdorrin @ 2011-12-13 21:48 ` Randy Brukardt 2011-12-14 18:28 ` Interfaces.Shift_Left awdorrin 0 siblings, 1 reply; 22+ messages in thread From: Randy Brukardt @ 2011-12-13 21:48 UTC (permalink / raw) "awdorrin" <awdorrin@gmail.com> wrote in message news:5f989095-5c1c-4b23-a538-d70f4718b4b1@l19g2000yqc.googlegroups.com... > The data being manipulated does start out as signed 32-bit integers - > its the Logical Shift operations in the Interfaces package that are > expecting Unsigned_32 types as input parameters. It does not make sense to "shift" numbers: "shift" is not an operation of a number. It does make sense to "shift" a bunch of bits. Ada allows treating an unsigned number as a "bunch of bits", thus modular types support "and", "or", and shifting. But Ada does not allow that for signed numbers. C programmers sometimes use shifting as a shortcut for multiplying or dividing by a power of 2. But this is premature optimization: any remotely decent compiler will do this automatically, without confusing the reader of the code. (Ever Ada compiler that I've examined the output of does this optimization.) (And this has the advantage of still getting overflow checks for multiplies, so there is a protection against getting the wrong answers by accident.) So, if the data is *really* numeric in nature, then the first choice is to write the operations in terms of multiply and divide. OTOH, if the data is not numeric, then the shifting probably is just used to pack data into a word. That's better done in Ada using representation clauses -- but in the interests of getting your program converted fast, you probably should leave well-enough alone and stick with the shifts. But in that case, the data type should be unsigned (there is no "number" involved). Anyway, I understand if you want to use Unchecked_Conversion as a quick-and-dirty hack -- those are often necessary in the real world. But you shouldn't think of that as the final solution; there is something fundementally wrong with needing to shift signed values, and it would be best to work out what the problem is an eliminate it. Randy. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-13 21:48 ` Interfaces.Shift_Left Randy Brukardt @ 2011-12-14 18:28 ` awdorrin 2011-12-14 22:49 ` Interfaces.Shift_Left Randy Brukardt 0 siblings, 1 reply; 22+ messages in thread From: awdorrin @ 2011-12-14 18:28 UTC (permalink / raw) I understand what you are saying and I do agree in theory. The situation is that bit shifting is being used to retrieve data of various bit lengths and positions from compound records. For instance, retrieving a 6-bit signed value from a 32-bit field. For the purposes of obtaining those 6 bits - sign is irrelevant, but that 6 bit value is then sent back to a calling process as an 'Int32' so I need the sign then. Given more time and funding, I would replace this logic with something that makes more sense, but a quick Unchecked_Conversion saves rewriting 15,000+ lines of code. :) ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-14 18:28 ` Interfaces.Shift_Left awdorrin @ 2011-12-14 22:49 ` Randy Brukardt 2011-12-15 9:51 ` Interfaces.Shift_Left Niklas Holsti 0 siblings, 1 reply; 22+ messages in thread From: Randy Brukardt @ 2011-12-14 22:49 UTC (permalink / raw) "awdorrin" <awdorrin@gmail.com> wrote in message news:a76daa61-49f7-4235-af65-11973a012f35@v29g2000yqv.googlegroups.com... >I understand what you are saying and I do agree in theory. > > The situation is that bit shifting is being used to retrieve data of > various bit lengths and positions from compound records. > > For instance, retrieving a 6-bit signed value from a 32-bit field. Right. This definitely should be done using record representation clauses if there is a choice. But of course if the code already exists, that might be too much. > For the purposes of obtaining those 6 bits - sign is irrelevant, but > that 6 bit value is then sent back to a calling process as an 'Int32' > so I need the sign then. Right. A record representation clause would do this correctly with no (visible) shifting, and it would be far less prone to errors. To take a quick example from my solitare solvers: Max_Score : constant := 1000; type Suits is (Diamonds, Hearts, Spades, Clubs); subtype Pip_Value is Natural range 1 .. 13; -- 1 = Ace, 13 = King. (I have names for these not shown here.) subtype Score_Value is Integer range -Max_Score..Max_Score; type Card is record Suit : Suits; Pip : Pip_Value; Score : Score_Value; end record; for Card use record Suit at 0 range 14..15; Pip at 0 range 10..13; Score at 0 range 0..9; end record; for Card'Size use 16; Great_Card : constant Card := (Suit => Spades, Pip => 1, Score => 800); Now, a reference to Great_Card.Score will give you a signed result, and the compiler will select the best set of shifts and masks for your target machine (not to mention combining them when possible). Much less complication, much easier to read, much less likely to make a mistake. > Given more time and funding, I would replace this logic with something > that makes more sense, but a quick Unchecked_Conversion saves > rewriting 15,000+ lines of code. :) I certainly understand, but personally I would guess that replacing the explicit shifting and masking with a record type would probably take me about the same time as writing all of the Unchecked_Conversion instances you would need. And there will be a lot less chance of error. YMMV, of course. BTW, if there are really 15000 lines that would get changed by this, there is a really bad lack of encapsulation with this code. The interfaces between Ada and other languages/hardware/OSes should always be made as narrow as possible, and always should go through a well-encapulated interface (so it is easy to change one side without distrubing the other). But I realize that you probably know this. Randy. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-14 22:49 ` Interfaces.Shift_Left Randy Brukardt @ 2011-12-15 9:51 ` Niklas Holsti 2011-12-16 0:23 ` Interfaces.Shift_Left Randy Brukardt 0 siblings, 1 reply; 22+ messages in thread From: Niklas Holsti @ 2011-12-15 9:51 UTC (permalink / raw) On 11-12-15 00:49 , Randy Brukardt wrote: > "awdorrin"<awdorrin@gmail.com> wrote in message > news:a76daa61-49f7-4235-af65-11973a012f35@v29g2000yqv.googlegroups.com... >> I understand what you are saying and I do agree in theory. >> >> The situation is that bit shifting is being used to retrieve data of >> various bit lengths and positions from compound records. >> >> For instance, retrieving a 6-bit signed value from a 32-bit field. > > Right. This definitely should be done using record representation clauses if > there is a choice. I'm sorry to say that I disagree, and now always use the shift-and-mask method. I used to be charmed by record representation clauses, until I wanted to write Ada 95 code that was portable between machines with different bit numbering orders. I know that it is claimed that record representation clauses can be written to be portable between different bit numberings. But in my opinion, the schemes that do not use the Bit_Order attribute make the representation clauses ugly and hard to write and read, while the RM language that describes the Bit_Order attribute and its effects has surpassed my understanding whenever I've tried to read it -- I simply could not be sure that it would have the effect that I wanted. I still would like to define the bit-level structure of data in a declarative way, rather than with field-extraction and field-insertion operations, but I have reluctantly concluded that the operational method is better for portable Ada programs, at least in my applications. Another factor in this decision is that in my applications, the raw data (machine instructions for various processors) can actually have several different structures (instruction formats), so an approach using record representation clauses needs as many different record types and unchecked conversions from the raw data (bit-strings or words) to the appropriate record type. The operational approach entirely avoids these conversions. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-15 9:51 ` Interfaces.Shift_Left Niklas Holsti @ 2011-12-16 0:23 ` Randy Brukardt 2011-12-18 20:47 ` Interfaces.Shift_Left Niklas Holsti 0 siblings, 1 reply; 22+ messages in thread From: Randy Brukardt @ 2011-12-16 0:23 UTC (permalink / raw) "Niklas Holsti" <niklas.holsti@tidorum.invalid> wrote in message news:9ktu5mFn31U1@mid.individual.net... > On 11-12-15 00:49 , Randy Brukardt wrote: >> "awdorrin"<awdorrin@gmail.com> wrote in message >> news:a76daa61-49f7-4235-af65-11973a012f35@v29g2000yqv.googlegroups.com... >>> I understand what you are saying and I do agree in theory. >>> >>> The situation is that bit shifting is being used to retrieve data of >>> various bit lengths and positions from compound records. >>> >>> For instance, retrieving a 6-bit signed value from a 32-bit field. >> >> Right. This definitely should be done using record representation clauses >> if >> there is a choice. > > I'm sorry to say that I disagree, and now always use the shift-and-mask > method. Might as well write in C then, this sort of code is complete, unmaintainable junk. > I used to be charmed by record representation clauses, until I wanted to > write Ada 95 code that was portable between machines with different bit > numbering orders. It's true, that's a problem. Luckily, it's not a real problem in practice for the vast majority of users, since pretty much all popular machines these days use the same bit numbering. > I know that it is claimed that record representation clauses can be > written to be portable between different bit numberings. But in my > opinion, the schemes that do not use the Bit_Order attribute make the > representation clauses ugly and hard to write and read, while the RM > language that describes the Bit_Order attribute and its effects has > surpassed my understanding whenever I've tried to read it -- I simply > could not be sure that it would have the effect that I wanted. It will have the right effect or be illegal. (At least that was my understanding.) The problem is that the non-default bit ordering makes it trivial to declare discontiguous (from the persepective of the default bit-ordering) components, and we didn't want to force compilers to support that sort of stuff. There is little customer demand for that sort of thing (most of the ones that exist are like you and gave up completely wanting more control than the language could possibly provide), so it didn't make sense to require the effort. > I still would like to define the bit-level structure of data in a > declarative way, rather than with field-extraction and field-insertion > operations, but I have reluctantly concluded that the operational method > is better for portable Ada programs, at least in my applications. > > Another factor in this decision is that in my applications, the raw data > (machine instructions for various processors) can actually have several > different structures (instruction formats), so an approach using record > representation clauses needs as many different record types and unchecked > conversions from the raw data (bit-strings or words) to the appropriate > record type. The operational approach entirely avoids these conversions. Of course, the vast majority of Unchecked_Conversions generate no code at all, so these conversions have no run-time impact and IMHO they're still more readable than a bunch of shifts or multiplies. Anyway, I understand that everyone's mileage may vary. I doubt that many applications have the problem of decoding data that are both in the wrong bit-order and are unknown at run-time. (Truth-in-advertising provision: most of the Janus/Ada compiler uses multiplies and divides to create machine instructions, because early versions of Janus/Ada had no support for record representation clauses or any other bit operations at all. We used assembler code whenever those operations were unavoidable -- hardly an ideal approach for portability reasons. Later versions (like the never-finished 68K and SPARC codegens) used record rep. clauses; I recall we had some issues with non-default bit-ordering but don't remember anymore how we solved them.) Randy. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-16 0:23 ` Interfaces.Shift_Left Randy Brukardt @ 2011-12-18 20:47 ` Niklas Holsti 2011-12-20 0:38 ` Interfaces.Shift_Left Randy Brukardt 0 siblings, 1 reply; 22+ messages in thread From: Niklas Holsti @ 2011-12-18 20:47 UTC (permalink / raw) On 11-12-16 02:23 , Randy Brukardt wrote: > "Niklas Holsti"<niklas.holsti@tidorum.invalid> wrote in message > news:9ktu5mFn31U1@mid.individual.net... >> On 11-12-15 00:49 , Randy Brukardt wrote: >>> "awdorrin"<awdorrin@gmail.com> wrote in message >>> news:a76daa61-49f7-4235-af65-11973a012f35@v29g2000yqv.googlegroups.com... >>>> I understand what you are saying and I do agree in theory. >>>> >>>> The situation is that bit shifting is being used to retrieve data of >>>> various bit lengths and positions from compound records. >>>> >>>> For instance, retrieving a 6-bit signed value from a 32-bit field. >>> >>> Right. This definitely should be done using record representation clauses >>> if >>> there is a choice. >> >> I'm sorry to say that I disagree, and now always use the shift-and-mask >> method. > > Might as well write in C then, this sort of code is complete, unmaintainable > junk. Ooh, harsh words. I'm trying not to take offence. Of course I hide the implementation in an "extract field" function with the bit numbers as parameters. My code typically decodes machine instructions from the instruction set of some processor; the user manual of that processor is the specification for my SW; the user manual normally shows the format of a given instruction by a figure of the instruction with the fields indicated by bit numbers; there is an immediate correspondence between this figure and the calls of the "extract field" functions. Very easy to write, check, and maintain, in my experience. >> I used to be charmed by record representation clauses, until I wanted to >> write Ada 95 code that was portable between machines with different bit >> numbering orders. > > It's true, that's a problem. Luckily, it's not a real problem in practice > for the vast majority of users, since pretty much all popular machines these > days use the same bit numbering. "All the world is a VAX -- no, an Intel -- no, an Xxx", eh? I do not want to write programs that have such an implementation dependency. I wouldn't go so far as to call such code "junk", but it would be as bad as assuming that Integer is 32 bits. >> the RM >> language that describes the Bit_Order attribute and its effects has >> surpassed my understanding whenever I've tried to read it -- I simply >> could not be sure that it would have the effect that I wanted. > > It will have the right effect or be illegal. (At least that was my > understanding.) I'm sure that is the intention. But as I haven't been able to understand the conditions under which Bit_Order works, I haven't dared to rely on it. Maybe I could understand Bit_Order if I tried harder, but then there's the other factor: >> Another factor in this decision is that in my applications, the raw data >> (machine instructions for various processors) can actually have several >> different structures (instruction formats), so an approach using record >> representation clauses needs as many different record types and unchecked >> conversions from the raw data (bit-strings or words) to the appropriate >> record type. The operational approach entirely avoids these conversions. > > Of course, the vast majority of Unchecked_Conversions generate no code at > all, so these conversions have no run-time impact Sure, run-time is no problem; the problem is having to write a lot of type declarations, plus their representation clauses. There's just much more text, more type names, more component names, which to me have little benefit. Each of these types and components would be used only once, in the Ada code that translates an instruction of that format into my internal representation. > and IMHO they're still > more readable than a bunch of shifts or multiplies. I agree, if the shifts and masks would be written in-line, which I don't do. I write calls to my "extract field" function instead, which I find very readable and easy to compare to the specification. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-18 20:47 ` Interfaces.Shift_Left Niklas Holsti @ 2011-12-20 0:38 ` Randy Brukardt 2011-12-20 2:18 ` Interfaces.Shift_Left Shark8 ` (2 more replies) 0 siblings, 3 replies; 22+ messages in thread From: Randy Brukardt @ 2011-12-20 0:38 UTC (permalink / raw) "Niklas Holsti" <niklas.holsti@tidorum.invalid> wrote in message news:9l71m2FlhuU1@mid.individual.net... > On 11-12-16 02:23 , Randy Brukardt wrote: >> "Niklas Holsti"<niklas.holsti@tidorum.invalid> wrote in message >> news:9ktu5mFn31U1@mid.individual.net... >>> On 11-12-15 00:49 , Randy Brukardt wrote: ... >>>> Right. This definitely should be done using record representation >>>> clauses >>>> if >>>> there is a choice. >>> >>> I'm sorry to say that I disagree, and now always use the shift-and-mask >>> method. >> >> Might as well write in C then, this sort of code is complete, >> unmaintainable >> junk. > > Ooh, harsh words. I'm trying not to take offence. Sorry, that wasn't really aimed at you. Your application (which has to process many foreign machine formats) is highly unusual, and I would not want most readers to take away the same "lesson" you learned, because it is wrong in general. But I realize that given the architecture of your system, having a "dirty" routine doing the conversion into the internal format might very well be the best solution. It's rarely possible to make that sort of code "pretty" because it has performance impliciations or just plain messy formats in the foreign systems. ... > Of course I hide the implementation in an "extract field" function with > the bit numbers as parameters. My code typically decodes machine > instructions from the instruction set of some processor; the user manual > of that processor is the specification for my SW; the user manual normally > shows the format of a given instruction by a figure of the instruction > with the fields indicated by bit numbers; there is an immediate > correspondence between this figure and the calls of the "extract field" > functions. Very easy to write, check, and maintain, in my experience. I wouldn't use an "extract field" function in my own code simply because Janus/Ada does not do inlining of subprograms. Thus the performance hit of such a function would be severe (it was a factor of 3 for code generation, I recall.) And thus in my code, this turned into a bunch of multiplies and divides, along with a nice ascii version of the diagram from the processor manual. It surely would have been better to put the diagram directly in the Ada code (we didn't have record rep. clauses in the early days of Janus/Ada, or I surely would have done so). The advantage, of course, is that the instruction description is only in the text once (as a record type declaration, which is quite readable), rather than twice (bit extracts in whatever form, plus some documentation of what they mean). >>> I used to be charmed by record representation clauses, until I wanted to >>> write Ada 95 code that was portable between machines with different bit >>> numbering orders. >> >> It's true, that's a problem. Luckily, it's not a real problem in practice >> for the vast majority of users, since pretty much all popular machines >> these >> days use the same bit numbering. > > "All the world is a VAX -- no, an Intel -- no, an Xxx", eh? Not at all. My understanding is that virtually all recent processors are little-endian (and all of the new processors in common use). I believe this is driven in part by the need of all machines to interoperate (unlike the little islands of the 1960s and 1970s). So I don't think we'll be seeing many new host machines using big-endian numbers (there are a few legacy systems still around, of course), especially as there is no real advantage of one system over the other. In a sense, this is similar to the 1's complement - 2's complement divide. If you have code that only works on 2's complement machines, it really doesn't matter anymore, but once upon a time, that would have been a big deal. I think we're seeing the same sort of thing with bit numbering and byte ordering (BTW, these two things are linked together, it's not sensible to swap only one and not the other -- otherwise your integer fields get broken into chunks). So it is not that big of a deal to use one system and ignore the other. Unless, of course, you are doing processing on/for one of those legacy systems (which seems to be in part your situation, again, your situation seems unusual to me). > I do not want to write programs that have such an implementation > dependency. I wouldn't go so far as to call such code "junk", but it would > be as bad as assuming that Integer is 32 bits. As I said above, I think it is more like assuming your machine is 2's complement. Not that big of a deal, but it matters if you need absolute portability. .... >>> Another factor in this decision is that in my applications, the raw data >>> (machine instructions for various processors) can actually have several >>> different structures (instruction formats), so an approach using record >>> representation clauses needs as many different record types and >>> unchecked >>> conversions from the raw data (bit-strings or words) to the appropriate >>> record type. The operational approach entirely avoids these conversions. >> >> Of course, the vast majority of Unchecked_Conversions generate no code at >> all, so these conversions have no run-time impact > > Sure, run-time is no problem; the problem is having to write a lot of type > declarations, plus their representation clauses. There's just much more > text, more type names, more component names, which to me have little > benefit. Each of these types and components would be used only once, in > the Ada code that translates an instruction of that format into my > internal representation. I view these declarations as a good stand-in for the documentation (comments) that I'd otherwise have to write. They're a lot more readable than shifts or multiplies! >> and IMHO they're still >> more readable than a bunch of shifts or multiplies. > > I agree, if the shifts and masks would be written in-line, which I don't > do. I write calls to my "extract field" function instead, which I find > very readable and easy to compare to the specification. Obviously, your mileage varies from mine. I presume you're not documenting "the specification" in the code, because otherwise you would have to write it twice (which would make the record types a lot more attactive). I wouldn't allow that in my code (I'm not going to make the reader go fumble with books or PDFs to understand the layout!), but of course YMMV. [Your extract operation will define the bits involved, but not the meaning, and I presume how you use the result will help explain the internal meaning, but not the original definition.] Anyway, let me repeat again: YMMV. Your application works for you, and that's fine. I just don't think that you should tell the world (most of whose applications are very different from yours) that record represenation clauses don't work. Because they're in the top 5 reasons to use Ada, and without them, Ada becomes just another programming language (with better syntax, but good luck convincing anyone of that). Randy. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-20 0:38 ` Interfaces.Shift_Left Randy Brukardt @ 2011-12-20 2:18 ` Shark8 2011-12-20 10:08 ` Interfaces.Shift_Left Dmitry A. Kazakov 2011-12-20 19:38 ` Interfaces.Shift_Left Niklas Holsti 2 siblings, 0 replies; 22+ messages in thread From: Shark8 @ 2011-12-20 2:18 UTC (permalink / raw) On Dec 19, 6:38 pm, "Randy Brukardt" <ra...@rrsoftware.com> wrote: > > Anyway, let me repeat again: YMMV. Your application works for you, and > that's fine. I just don't think that you should tell the world (most of > whose applications are very different from yours) that record represenation > clauses don't work. Because they're in the top 5 reasons to use Ada, and > without them, Ada becomes just another programming language (with better > syntax, but good luck convincing anyone of that). > > Randy. What are the other four? ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-20 0:38 ` Interfaces.Shift_Left Randy Brukardt 2011-12-20 2:18 ` Interfaces.Shift_Left Shark8 @ 2011-12-20 10:08 ` Dmitry A. Kazakov 2011-12-20 19:38 ` Interfaces.Shift_Left Niklas Holsti 2 siblings, 0 replies; 22+ messages in thread From: Dmitry A. Kazakov @ 2011-12-20 10:08 UTC (permalink / raw) On Mon, 19 Dec 2011 18:38:53 -0600, Randy Brukardt wrote: [It is imperative vs. declarative debate] > Obviously, your mileage varies from mine. I presume you're not documenting > "the specification" in the code, because otherwise you would have to write > it twice (which would make the record types a lot more attactive). It must be done anyway, because when it comes to the protocols they are normally defined not in bits and offsets, but in some quite ugly quasi-language. Extraction of bits in an imperative manner as Niklas does, I do, and I bet many people dealing with protocols do, serves documentation purpose better, than translation from one cryptic declarative language to another (of Ada representation clauses). And fields is just a minor problem. The protocols have lots of other encoding stuff, which simply cannot be expressed by any clause. E.g. chain codes, padding, check sums etc. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-20 0:38 ` Interfaces.Shift_Left Randy Brukardt 2011-12-20 2:18 ` Interfaces.Shift_Left Shark8 2011-12-20 10:08 ` Interfaces.Shift_Left Dmitry A. Kazakov @ 2011-12-20 19:38 ` Niklas Holsti 2011-12-20 20:46 ` Interfaces.Shift_Left Niklas Holsti ` (2 more replies) 2 siblings, 3 replies; 22+ messages in thread From: Niklas Holsti @ 2011-12-20 19:38 UTC (permalink / raw) On 11-12-20 02:38 , Randy Brukardt wrote: > "Niklas Holsti"<niklas.holsti@tidorum.invalid> wrote in message > news:9l71m2FlhuU1@mid.individual.net... >> On 11-12-16 02:23 , Randy Brukardt wrote: >>> "Niklas Holsti"<niklas.holsti@tidorum.invalid> wrote in message >>> news:9ktu5mFn31U1@mid.individual.net... >>>> On 11-12-15 00:49 , Randy Brukardt wrote: > ... >>>>> Right. This definitely should be done using record representation >>>>> clauses >>>>> if >>>>> there is a choice. >>>> >>>> I'm sorry to say that I disagree, and now always use the shift-and-mask >>>> method. >>> >>> Might as well write in C then, this sort of code is complete, >>> unmaintainable junk. >> >> Ooh, harsh words. I'm trying not to take offence. > > Sorry, that wasn't really aimed at you. Ok. > Your application (which has to > process many foreign machine formats) is highly unusual, and I would not > want most readers to take away the same "lesson" you learned, because it is > wrong in general. I was unclear: I did not mean to claim that one should always avoid record representation clauses, only to say that IMO they are not always the best solution. I should have written a more balanced comment. > But I realize that given the architecture of your system, having a "dirty" > routine doing the conversion into the internal format might very well be the > best solution. The "extract field" function is not very dirty; two shift operations on an unsigned word. And completely portable (as long as Interfaces defines an unsigned type of the required length). > I wouldn't use an "extract field" function in my own code simply because > Janus/Ada does not do inlining of subprograms. Thus the performance hit of > such a function would be severe (it was a factor of 3 for code generation, I > recall.) I haven't measured it, but I don't believe that the "extract field" operation is an important slow-down for me, even if not inlined. The bottle-necks are elsewhere in my app. An "insert field" operation has more overhead than an "extract field" operation. But my application only needs to unpack records with bit-fields, not generate them. > (we didn't have record rep. clauses in the early days of Janus/Ada, > or I surely would have done so). Probably I would have used record representation clauses there, too, since I assume that Janus/Ada was meant to run on and for Intel processors, so there was little cause to fear a change in bit numbering. And of course you know exactly how Bit_Order works in Janus/Ada. Even today, if I were to write an Ada program to run on a particular microcontroller and access the on-chip peripheral control registers, I would use record representation clauses to describe the structure of those registers. The code would probably make many accesses to each record component, making a procedural approach more cumbersome, and there would be no need for portability with regard to bit numbering, since this code would be tied to this microcontroller anyway. > The advantage, of course, is that the instruction description is only in the > text once (as a record type declaration, which is quite readable), rather > than twice (bit extracts in whatever form, plus some documentation of what > they mean). I don't duplicate the record specifications (= the target processor user manual) in my code. The calls of the "extract field" function occur in contexts that give sufficient documentation, IMO. For example, a line like Rd => Register (Word, 15, 12), means that the value of the internal-representation component Rd is taken from bits 15..12 in the input Word. (The name "Rd" is the same as used in the processor user manual for this field, of course. The Register function is a variant of "extract field" that returns the proper type for Rd.) >>>> I used to be charmed by record representation clauses, until I wanted to >>>> write Ada 95 code that was portable between machines with different bit >>>> numbering orders. >>> >>> It's true, that's a problem. Luckily, it's not a real problem in practice >>> for the vast majority of users, since pretty much all popular machines >>> these >>> days use the same bit numbering. >> >> "All the world is a VAX -- no, an Intel -- no, an Xxx", eh? > > Not at all. My understanding is that virtually all recent processors are > little-endian (and all of the new processors in common use). ... > In a sense, this is similar to the 1's complement - 2's complement divide. I get your point. I don't really know, myself, how the trends are going. If big-endian bit-numbering is as rare as 1's complement, you have a good point. > Unless, of course, you are doing processing on/for one of those legacy > systems (which seems to be in part your situation, again, your situation > seems unusual to me). My Ada code was originally written for big-endian SPARC workstations and needed porting to little-endian Intel PCs. I believe the SPARC is still an actively developed architecture. > I view these declarations as a good stand-in for the documentation > (comments) that I'd otherwise have to write. ... > I presume you're not documenting > "the specification" in the code, because otherwise you would have to write > it twice (which would make the record types a lot more attactive). That's right, I just write comments that reference the existing specification doc that defines the record formats, often naming a specific chapter, section, or page. > I wouldn't allow that in my code (I'm not going to make the reader go fumble > with books or PDFs to understand the layout!), but of course YMMV. The mileage varies, indeed: I would consider it downright dangerous to copy the specs (manually) into the code, since this can introduce errors. I don't see any need for a reader to "understand" the layout, since the layout has no impact on meaning. If a reader wants to check that the code uses the right bit numbers and the right interpretation of the fields, it is much better IMO to force the reader to look at the original specs. > [Your extract operation will define the bits involved, but not the > meaning, and I presume how you use the result will help explain the > internal meaning, but not the original definition.] That's right. Each call of an extract operation typically defines the value of a component of the internal representation. The meaning of this component is documented in the type declarations for the internal representation. > Anyway, let me repeat again: YMMV. Your application works for you, and > that's fine. I just don't think that you should tell the world (most of > whose applications are very different from yours) that record represenation > clauses don't work. That was not my intent. The original question was something about "retrieving a 6-bit signed value from a 32-bit field"; you said that record representation clauses "definitely should be used" for this; I wanted to protest against the "definitely", with reasons. I think we understand each other now. > Because they're in the top 5 reasons to use Ada, Is that based on some survey of reasons why Ada is used? That would be interesting. I agree with that ranking only for some Ada applications -- the traditional embedded, bare-machine programs that access hardware registers. Programs that deal with communication protocols may also qualify. And even there, I would not put record representation clauses close to the top of the 5 top reasons. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-20 19:38 ` Interfaces.Shift_Left Niklas Holsti @ 2011-12-20 20:46 ` Niklas Holsti 2011-12-20 21:13 ` Interfaces.Shift_Left Simon Wright 2011-12-20 21:08 ` Interfaces.Shift_Left Simon Wright 2011-12-20 23:36 ` Interfaces.Shift_Left Randy Brukardt 2 siblings, 1 reply; 22+ messages in thread From: Niklas Holsti @ 2011-12-20 20:46 UTC (permalink / raw) Making a comment on my own post: On 11-12-20 21:38 , Niklas Holsti wrote: > On 11-12-20 02:38 , Randy Brukardt wrote: >> >> Not at all. My understanding is that virtually all recent processors are >> little-endian (and all of the new processors in common use). > > My Ada code was originally written for big-endian SPARC workstations and > needed porting to little-endian Intel PCs. I believe the SPARC is still > an actively developed architecture. ... but I just learned that the newer SPARCs are "bi-endian" and able to run in either big- or little-endian mode. So little-endian is gaining, which may in the end make little-endian record representation clauses portable, in practice. Good if that happens. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-20 20:46 ` Interfaces.Shift_Left Niklas Holsti @ 2011-12-20 21:13 ` Simon Wright 0 siblings, 0 replies; 22+ messages in thread From: Simon Wright @ 2011-12-20 21:13 UTC (permalink / raw) Niklas Holsti <niklas.holsti@tidorum.invalid> writes: > Making a comment on my own post: > > On 11-12-20 21:38 , Niklas Holsti wrote: >> On 11-12-20 02:38 , Randy Brukardt wrote: >>> >>> Not at all. My understanding is that virtually all recent processors are >>> little-endian (and all of the new processors in common use). >> >> My Ada code was originally written for big-endian SPARC workstations and >> needed porting to little-endian Intel PCs. I believe the SPARC is still >> an actively developed architecture. > > ... but I just learned that the newer SPARCs are "bi-endian" and able > to run in either big- or little-endian mode. So little-endian is > gaining, which may in the end make little-endian record representation > clauses portable, in practice. Good if that happens. The same is I believe true of PowerPC and ARM. But it really depends on the OS - and the peripherals! Dealing with a LE-designed peripheral vs a BE processor/OS was fun. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-20 19:38 ` Interfaces.Shift_Left Niklas Holsti 2011-12-20 20:46 ` Interfaces.Shift_Left Niklas Holsti @ 2011-12-20 21:08 ` Simon Wright 2011-12-20 23:26 ` Interfaces.Shift_Left Randy Brukardt 2011-12-20 23:36 ` Interfaces.Shift_Left Randy Brukardt 2 siblings, 1 reply; 22+ messages in thread From: Simon Wright @ 2011-12-20 21:08 UTC (permalink / raw) Niklas Holsti <niklas.holsti@tidorum.invalid> writes: > I get your point. I don't really know, myself, how the trends are > going. If big-endian bit-numbering is as rare as 1's complement, you > have a good point. As you noted below, there's SPARC; and in rugged systems there are still quite a lot of big-endian processors about (6 BE to 8 LE from GE Intelligent Platforms, for example). ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-20 21:08 ` Interfaces.Shift_Left Simon Wright @ 2011-12-20 23:26 ` Randy Brukardt 0 siblings, 0 replies; 22+ messages in thread From: Randy Brukardt @ 2011-12-20 23:26 UTC (permalink / raw) "Simon Wright" <simon@pushface.org> wrote in message news:m24nwv7xxz.fsf@pushface.org... > Niklas Holsti <niklas.holsti@tidorum.invalid> writes: > >> I get your point. I don't really know, myself, how the trends are >> going. If big-endian bit-numbering is as rare as 1's complement, you >> have a good point. > > As you noted below, there's SPARC; and in rugged systems there are still > quite a lot of big-endian processors about (6 BE to 8 LE from GE > Intelligent Platforms, for example). Yes, they're about, but mostly they're older designs. (At least, that is the way it was explained to me; I haven't studied processors for years, early SPARC being the last one that I coded for.) Randy. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-20 19:38 ` Interfaces.Shift_Left Niklas Holsti 2011-12-20 20:46 ` Interfaces.Shift_Left Niklas Holsti 2011-12-20 21:08 ` Interfaces.Shift_Left Simon Wright @ 2011-12-20 23:36 ` Randy Brukardt 2011-12-21 0:44 ` Interfaces.Shift_Left Georg Bauhaus 2011-12-21 7:23 ` Interfaces.Shift_Left AdaMagica 2 siblings, 2 replies; 22+ messages in thread From: Randy Brukardt @ 2011-12-20 23:36 UTC (permalink / raw) "Niklas Holsti" <niklas.holsti@tidorum.invalid> wrote in message news:9lc6bqFfhrU1@mid.individual.net... ... > Is that based on some survey of reasons why Ada is used? That would be > interesting. I agree with that ranking only for some Ada applications -- > the traditional embedded, bare-machine programs that access hardware > registers. Programs that deal with communication protocols may also > qualify. And even there, I would not put record representation clauses > close to the top of the 5 top reasons. No, just my gut feeling. At lot of the things that make Ada unique aren't things that you really can sell to outsiders (that is, non-Ada users that might be interested in using Ada). For instance, I find that the syntax of Ada has just the right level of verbosity (not so much as to be a pain, not so little as to allow one to write something other than what they meant to be legal). Most languages (especially C-based syntaxes) don't have enough. But I doubt I'm going to convince many others of that, at least not until they've had the experience of using Ada for a while. Another truly valuable feature of Ada is the complete coverage rule for case statements, aggregates, and the like. The amount of time that it can save when adding a new kind of thing (enumeration literal, record component, etc.) is amazing. (As the compiler points out the places you've forgotten to change; errors of omission are by far the hardest to find.) But again, this is a tough sell until you've had the compiler find errors for you. Most of the big picture things (like packages and generics) are available in other languages, and Ada's advantages with them are subtle (physical separation of interface and implementation; the contract model of generic) -- these are also not that easy to describe to potential users. The net effect of all of these smallish things leads to a much bigger advantage when put together -- but there is nothing "sexy" about any of them. Representation clauses in general at least are easy to explain and almost everybody remembers times when they would have preferred that the compiler did the packing/unpacking of fields. So they make a good lead for the advantages of Ada. Randy. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-20 23:36 ` Interfaces.Shift_Left Randy Brukardt @ 2011-12-21 0:44 ` Georg Bauhaus 2011-12-21 7:23 ` Interfaces.Shift_Left AdaMagica 1 sibling, 0 replies; 22+ messages in thread From: Georg Bauhaus @ 2011-12-21 0:44 UTC (permalink / raw) On 21.12.11 00:36, Randy Brukardt wrote: > > Another truly valuable feature of Ada is the complete coverage rule for case > statements, aggregates, and the like. The amount of time that it can save > when adding a new kind of thing (enumeration literal, record component, > etc.) is amazing. (As the compiler points out the places you've forgotten to > change; errors of omission are by far the hardest to find.) But again, this > is a tough sell until you've had the compiler find errors for you. Coverage of all cases is already being sold with other, uhum, languages: The mechanism appears to be effective, but technically and economically, and is catering to both types of programmers: those who love to know the sharpness of C tools and to software engineers (pragmatic style). "Static analysis" allows the compilers to warn about cases not covered in switches in imperative C languages. Similarly, warnings about argument pattern matching not being exhaustive is about the same for the ML family of functional languages; advanced compilers will issue the warnings when translating the definition of function by cases. Thus, the programmers who know what they are doing (who therefore do not need Ada) can continue to know what they are doing *and* turn on warnings about coverage *as* *needed*. No bullying compiler is in the way, as is always the case with Ada.(*) When no one is listening, the makers of static analysis tools might even note that coverage rules were always present in Ada. Creating and using analysis tools adds flexibility, though, if rules are left informal in the respective virtual languages that the tools will establish. So each of the vendors can define their own informal language tacked onto the respective language. Everyone is happy, members of the virtual in-group of tool users share in a gentlemen's agreement, and no language standard gets in the way of creative business. All of this is possible without dragging in that dated, expensive government language. :-) __ (*) Reminds me of a story told by Richard Riehle about a big floor cleaning device that was really easy to push in one direction or other but only if you learn how to operate the massive thing. Then, a single finger would suffice. But why buy a floor cleaning device if brooms and rags are so much cheaper? ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Interfaces.Shift_Left 2011-12-20 23:36 ` Interfaces.Shift_Left Randy Brukardt 2011-12-21 0:44 ` Interfaces.Shift_Left Georg Bauhaus @ 2011-12-21 7:23 ` AdaMagica 1 sibling, 0 replies; 22+ messages in thread From: AdaMagica @ 2011-12-21 7:23 UTC (permalink / raw) On 21 Dez., 00:36, "Randy Brukardt" <ra...@rrsoftware.com> wrote: > ... At lot of the things that make Ada unique aren't > things that you really can sell to outsiders (that is, non-Ada users that > might be interested in using Ada). I think the paper John W. McCormick\vUniversity of Northern Iowa\vSoftware Engineering Education: On the Right Track http://www.crosstalkonline.org/storage/issue-archives/2000/200008/200008-McCormick.pdf has shown that the following basic Ada features were vital for the success of Ada vs. C: Modeling of Scalar Objects Strong Typing Range Constraints Enumerations Attributes like 'Range ... No need for Pointers Parameter modes for data flow Named Parameter Assoziation Flexible array index ranges But are these sexy? You have to have used them to estimate the value... ^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2011-12-21 7:29 UTC | newest] Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2011-12-12 22:30 Interfaces.Shift_Left awdorrin 2011-12-12 23:34 ` Interfaces.Shift_Left Simon Wright 2011-12-13 1:36 ` Interfaces.Shift_Left Adam Beneschan 2011-12-13 12:00 ` Interfaces.Shift_Left Brian Drummond 2011-12-13 13:15 ` Interfaces.Shift_Left awdorrin 2011-12-13 21:48 ` Interfaces.Shift_Left Randy Brukardt 2011-12-14 18:28 ` Interfaces.Shift_Left awdorrin 2011-12-14 22:49 ` Interfaces.Shift_Left Randy Brukardt 2011-12-15 9:51 ` Interfaces.Shift_Left Niklas Holsti 2011-12-16 0:23 ` Interfaces.Shift_Left Randy Brukardt 2011-12-18 20:47 ` Interfaces.Shift_Left Niklas Holsti 2011-12-20 0:38 ` Interfaces.Shift_Left Randy Brukardt 2011-12-20 2:18 ` Interfaces.Shift_Left Shark8 2011-12-20 10:08 ` Interfaces.Shift_Left Dmitry A. Kazakov 2011-12-20 19:38 ` Interfaces.Shift_Left Niklas Holsti 2011-12-20 20:46 ` Interfaces.Shift_Left Niklas Holsti 2011-12-20 21:13 ` Interfaces.Shift_Left Simon Wright 2011-12-20 21:08 ` Interfaces.Shift_Left Simon Wright 2011-12-20 23:26 ` Interfaces.Shift_Left Randy Brukardt 2011-12-20 23:36 ` Interfaces.Shift_Left Randy Brukardt 2011-12-21 0:44 ` Interfaces.Shift_Left Georg Bauhaus 2011-12-21 7:23 ` Interfaces.Shift_Left AdaMagica
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox