[comp.lang.c] Generalizing Integers

phipps@garth.UUCP (Clay Phipps) (05/03/89)

[The postings referenced below, the 1st of which I missed in original form,
appeared in "comp.arch", for some reason; apologies if this is redundant]

In article <3899@ficc.uu.net>, 
peter@ficc.uu.net | uunet.uu.net!ficc!peter (Peter da Silva) writes:
>In article <10377@polyslo.CalPoly.EDU>, 
>cquenel@polyslo.CalPoly.EDU (36 more school days) writes:
>> In 9424 peter@ficc.uu.net (Peter da Silva) sez:
>> >I've suggested this before. I think syntax like:
>> >	int:32	x, y;
>> >	int:36	z;	/* Unisys 1100 compatibility :-> */
>> >	int	a:8, b:9, c:6;
>>
>>[An apparent suggestion that new primitive types be created for C, e.g.:]
>> 	int32_t x,y;
>> 	int16_t c;
>>would probably raise a lot fewer hackles.
>
>... the semantics are not quite as good as int:n would be.
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
Agreed.  I realize that this is a C-related posting, but has anyone 
yet pointed out that PL/I had relevant features a quarter-century ago ?
The following suggests how that might apply to C.

Da Silva's original examples would be as follows in their tersest form:

    dcl (x, y) fixed bin(31),
        z      fixed bin(35),  /* Unisys/UNIVAC 1100 fullword */
        a      fixed bin(7),
        b      fixed bin(8),
        c      fixed bin(5);

The numbers above are coded as 1 less than above,
but yield the same representation, because the sign bits were implicit
in PL/I -- there was no notion of unsigned binary fixed-point numbers,
a.k.a. unsigned integers.  However, if any FORTRAN or COBOL scalar data 
types were wanting for support in PL/I, I have forgotten what they were.
PL/I also allowed specification of a radix point anywhere in the variable,
e.g.: "fixed bin(31,31)" would indicate that all bits were binary fraction
bits, such that a 32-bit word with the sign bit on and other bits off
would have the value -1.  I doubt that there would be much interest in 
providing arbitrary radix-point placement for data in C.

>For example, 1+(unsigned int:3)7 should be 0. 

I am not up on the fine points of C semantics, so maybe the example
is adequate, but I think you should require something like
    (unsigned int:3)(1+7)
to more clearly indicate the relation of the cast to the expression 
computation.  Otherwise, you will have ambiguity about what is intended
to be done if the expression is assigned to a wide assignment target,
e.g.: any target into which the representation for 8 fits completely. 

PL/I had conversion functions for which precision could be specified, e.g.:
    BINARY(1+7,3)
but PL/I was notorious for the surprises provided by its conversion rules
(which were explicitly *not* standardized), partially a consequence
of defaulting "fixed" to decimal (i.e.: BCD), and (I think) "binary" to 
floating-point, resulting in treatment of "7" as *decimal*, not binary.  
Fixed binary 7, a.k.a. signed integer 7, needed to be coded as "7b" 
(no quotes in the code).  Therefore, it might be necessary with some of 
the "obvious choices" of conversion functions to use that ugly PL/I 
binary-constant notation:
    PRECISION(1b+7b,3)
    FIXED(1b+7b,3)
Fortunately, C is not hindered by a perceived need to provide for BCD, 
and assuming little interest in the arbitrary placement of a radix-point 
in C "int" data, so any conversion rules that needed to be devised 
to support da Silva's idea could probably avoid the surprises that 
can make expression evaluation and conversions so aggravating in PL/I.

The casts suggested by da Silva are certainly preferable to collections of 
predefined conversion functions for languages (such as C) where user-defined 
data types are supported.  I wish Wirth had thought of that when designing 
Pascal.  PL/I doesn't provide named data types, although its "like" attribute 
comes close to that.

>It'd also be a boon for people porting code to weird machines... 
>sometimes you really need an int with a power-of-2 size,
>and it's a pain to emulate that by hand on a 36-bit machine.

ANS PL/I [ANSI X3.53-1976] defined a "default" statement, e.g.:
    default (fixed & bin) precision(31);  /* for IBM 360 & VAX */
    default (fixed & bin) precision(35);  /* for Unisys 1100 & Honeywell */
in which anything declared as both "fixed" and "bin" is assigned either
31 bits + sign, or 35 bits + sign, respectively.  This makes it possible
to ease porting in advance, by not coding the precision for declarations 
of standard-sized integers, declaring them as "fixed bin" only, 
limiting coding of parenthesized precision attributes to declarations 
for which they were independent of target architecture,
e.g.: network communications protocols.
Has the ANSI C committee provided anything like this ?

This discussion isn't very architecturish any more.
I have redirected follow-ups to "comp.lang.misc" and "comp.lang.c";
I encourage follow-ups to those to be directed to only one or the other,
depending upon how the discussion proceeds.
-- 
[The foregoing may or may not represent the position, if any, of my employer, ]
[ who is identified solely to allow the reader to account for personal biases.]
                                              
Clay Phipps                                {ingr,pyramid,sri-unix}!garth!phipps
Intergraph APD, 2400#4 Geng Road, Palo Alto, CA 93403              415/494-8800

mat@mole-end.UUCP (Mark A Terribile) (05/05/89)

> >> >	int:32	x, y;
> >> >	int:36	z;	/* Unisys 1100 compatibility :-> */
> >> >	int	a:8, b:9, c:6;

> >... the semantics are not quite as good as int:n would be.
>                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
> Agreed.  I realize that this is a C-related posting, but has anyone 
> yet pointed out that PL/I had relevant features a quarter-century ago ?
 
>     dcl (x, y) fixed bin(31),
>         z      fixed bin(35),  /* Unisys/UNIVAC 1100 fullword */
>         a      fixed bin(7),
>         b      fixed bin(8),
>         c      fixed bin(5);

See the example on pp 23-25 of Kernighan and Plaugher, *The Elements of
Programming Style*, second edition.

The problem with the PL/I approach is that the programmer is encouraged to
think of such declarations as ``normal.''  The results are strange conversions
leading to hard-to-find, hard-to-predict bugs which occur on boundaries that
cannot be easily guessed at in either inspection, walk-through, or white-box
testing, and leading also to extra code size and execution costs.

Bringing the complexity of code, seen as a cultural phenomanon, under some
kind of control required going to a simpler model of computation, required
going from PL/I to B.  As the limits of the simpler model(s) were discovered,
they were expanded incrementally, first by going to C and then by extending
C bit by bit.

The present ``mental model'' conjured up by bitfields is a model of an
exceptional or special case which is used when certain tradeoffs can be
accepted, and not otherwise.  For the moment, it does seem to be the best
way to view the bitfield.

PL/I did a lot of things.  It did a surprising number of them right.  It did
even more almost right.  That wasn't good enough, though.
-- 

(This man's opinions are his own.)
From mole-end				Mark Terribile

schow@bnr-public.uucp (Stanley Chow) (05/08/89)

In article <166@mole-end.UUCP> mat@mole-end.UUCP (Mark A Terribile) writes:
> [...]
>The problem with the PL/I approach is that the programmer is encouraged to
>think of such declarations as ``normal.''  The results are strange conversions
>leading to hard-to-find, hard-to-predict bugs which occur on boundaries that
>cannot be easily guessed at in either inspection, walk-through, or white-box
>testing, and leading also to extra code size and execution costs.
>

It seems to me that the declaration of integers can be seperated from the
conversion rules. PL/I happens to have conversion rules that make life very
interesting. This does not mean the *approach* is bad, merely PL/I did not
do this aspect right.

If you claim *all* such attempts are doomed to failure, then I take serious
issue with it.


>Bringing the complexity of code, seen as a cultural phenomanon, under some
>kind of control required going to a simpler model of computation, required
>going from PL/I to B.  As the limits of the simpler model(s) were discovered,
>they were expanded incrementally, first by going to C and then by extending
>C bit by bit.
>

I suggest that the model may be complex, as long as it is easy to reason
within that model. For example, Turing machines are very simple, but I find
it very difficult to do anything with them. On the other hand, LR(k) grammers
are far from simple, but I can write useful parsers with them.



Stanley Chow        BitNet:  schow@BNR.CA
BNR		    UUCP:    ..!psuvax1!BNR.CA.bitnet!schow
(613) 763-2831		     ..!utgpu!bnr-vpa!bnr-fos!schow%bnr-public
I am just a small cog in a big machine. I don't represent nobody.