Christoph Karl Walter Grein
Alexeus the brave, a keen salesman, laden with valuable bits galore
package Alexeus is type Money is range -2**15 .. 2**15-1; for Money’Size use 16; subtype Cash is Money range 0 .. Money’Last; end Alexeus;
gets about a lot on his journeys through Ada land and thus has to exchanges his bits many a time into a local currency. It so happens that he arrives at a frontier where crafty Prokrustes runs an exchange office. He offers our friend Alexeus the following exchange agreement:
with Ada.Unchecked_Conversion; with Alexeus, Foreign; use Alexeus, Foreign; package Prokrustes is function Exchange is new Ada.Unchecked_Conversion (Cash, Word); function Exchange is new Ada.Unchecked_Conversion (Word, Cash); end Prokrustes;
with the foreign currency
package Foreign is type Byte is mod 2**8; for Byte'Size use 8; type Word is array (1 .. 2) of Byte; end Foreign;
In the small print, there is a hint:
Take care that your source and target types have the same size.
"Of course, that's OK", thinks Alexeus, exchanges his bits at Prokrustes', travels through the country and does his business with sound profit. Finally he again arrives at Prokrustes' exchange office and wants to transfer his cash back into his home currency.
Crafty Prokrustes, sly rascal that he is (offspring of an ancient burglar family after all), in the meantime has replaced his exchange machine with one of a different manufacturer. Alexeus tallying his change doesn't believe his eyes: Prokrustes has cheated our poor salesman by half of his bits (according to the slogan: Who's gonna rob a bank if running one is a bonanza).
What's happening here? Let's have a closer look at the two exchange machines. Compiler_1 is the machine used on entry, Compiler_2 used on exit *.
Exchange (5) = (0, 5) -- Entry Exchange ((0, 5)) = 5
Exchange (5) = (0, 10) Exchange ((0, 10)) = 5 -- Exit
Compiler_1 works as naïve Alexeus expects; in contrast, Compiler_2 doubles respectively halves the values. (It goes without saying that Prokrustes knows quite well when to use which machine, to wit Compiler_1 on entry, Compiler_2 on exit.)
If only Alexeus had paid attention to the warning. His cash is nonnegative, hence needs only 15 bits for representation, number 16 is the sign: Cash'Size = 15, and this is exactly what the compilers wanted to express with their warnings (the small print in our little story).
Alexeus might even have been aware of this, but he said to himself: "Bosh, the compiler's nuts; objects of the subtype Cash still use 16 bits." And he's correct (for stand-alone objects), alas for the unchecked type conversion, there is this darn rule allowing to tap an exact number of bits. His error is pardonable though because he still uses Ada83 where the RM is not so clear as one would like [RM_83 13.7.2(5), 13.10.2(2)]. All in all, Ada95 is much more elaborate [RM_95 13.3(45,47), 13.9(6)].
The first machine now grabs the bits aligned to the LSB, the other to the MSB losing the LSB, which amounts to an integer division by 2. Both is legal since the RM only prescribes what has to happen with equally sized subtypes; everything else is unspecified.
Back to our story.
Alexeus, not being a match to hardened in many a raid Prokrustes, with hot feed and hoppingly mad runs to his old friend Theseus, a mighty lawyer, who forces evil Prokrustes to sign a new contract:
function Exchange is new Ada.Unchecked_Conversion (Money, Word ); function Exchange is new Ada.Unchecked_Conversion (Word , Money);
And lo and behold, Alexeus has back his money (oh well, except for the horrendous fee he has to pay to the modern robber-knight Theseus).
* No compiler manufacturers named; but this is from real embedded code.
Appeared in SWTT 27.3 (August 2007).
|Contents||© Copyright 2017 C.K.W. Grein|