* 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 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 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 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