[comp.lang.c] A bad design decision early on in ANSI C.

peter@sugar.UUCP (Peter da Silva) (12/28/87)

I would like to suggest removing a "feature" from 'C'.

Structure assignment/passing.

Unless you're going to go all the way and allow structures to be fully first
class objects (and presumably provide a way to overload operators so you can
do this meaningfully), it just adds confusion. It doesn't add any functionality
to the language over passing pointers and copying data. Usually I do that
anyway, since I know malloc() won't blow out my stack.

The worst effect, passing a structure instead of a pointer (or vice versa)
can be dealt with by function prototyping... but in the meanwhile there are
compilers out there that implement structure passing but not function
prototyping. A simple typo (leaving out an &) can ruin your whole day.

I still get bitten by this bug every now and then.

At least compiler designers should provide a switch to turn it off.
-- 
-- Peter da Silva  `-_-'  ...!hoptoad!academ!uhnix1!sugar!peter
-- Disclaimer: These U aren't mere opinions... these are *values*.

pardo@uw-june.UUCP (David Keppel) (12/28/87)

[Structure assignment passing]

I vote for keeping it.  I have had to suffer through a C compiler that
didn't do this when I *wanted* to pass whole structures on the stack.

There are also a number of compilers (such as B*rkeley Pascal) that pass
"by value" arguments by value.  To maintain compatability with them it is
necessary to have some mechanism for pushing blocks of things on the stack
in the function call list.

	;-D on  ("noalias considered sailaon")  Pardo

ark@alice.UUCP (12/28/87)

In article <1322@sugar.UUCP>, peter@sugar.UUCP writes:
> I would like to suggest removing a "feature" from 'C'.
> 
> Structure assignment/passing.

That would break a lot of programs, including
C programs generated by the C++ compiler.

kimcm@ambush.UUCP (Kim Chr. Madsen) (12/29/87)

pardo@uw-june.UUCP (David Keppel) writes:
>[Structure assignment passing]

>I vote for keeping it.  I have had to suffer through a C compiler that
>didn't do this when I *wanted* to pass whole structures on the stack.

>There are also a number of compilers (such as B*rkeley Pascal) that pass
>"by value" arguments by value.  To maintain compatability with them it is
>necessary to have some mechanism for pushing blocks of things on the stack
>in the function call list.

It can't be the objective of C (whether ANSI or not) to be compatible
with other programming languages or their compilers. Although I agree
that it is a nice feature - but dangerous on some systems:

	1) Forget the & when passing a pointer blows your program.
	2) Passing of huge structures may bomb the stack on small systems.


					Happy New Year
					Kim Chr. Madsen.

rbutterworth@watmath.waterloo.edu (Ray Butterworth) (12/29/87)

In article <1322@sugar.UUCP>, peter@sugar.UUCP (Peter da Silva) writes:
> I would like to suggest removing a "feature" from 'C'.
> Structure assignment/passing.
> ... A simple typo (leaving out an &) can ruin your whole day.
> I still get bitten by this bug every now and then.
> At least compiler designers should provide a switch to turn it off.

Try using LINT.
It's really quite good at telling you when you have mismatched
arguments.

OWENSJ%VTVM1.BITNET@CUNYVM.CUNY.EDU (John Owens) (12/30/87)

>I would like to suggest removing a "feature" from 'C'.
>
>Structure assignment/passing.
>
>Unless you're going to go all the way and allow structures to be fully first
>class objects (and presumably provide a way to overload operators so you can
>do this meaningfully), it just adds confusion.

I disagree.  I use structure assignment quite often; it's definitely
a useful abstraction.  I think that

        pa[i]->xyz = input_structure

is much clearer than either

        bcopy(&pa[i]->xyz,&input_structure,sizeof(input_structure));

which requires quite a bit of visual decoding (and please, no flames
if I have arguments in the wrong order), or

        pa[i]->xyz.ab_next = input_structure.ab_next;
        pa[i]->xyz.ab_count= input_structure.ab_count;
        pa[i]->xyz.ab_flag = input_structure.ab_flag;
        pa[i]->xyz.ab_name = input_structure.ab_name;
        pa[i]->xyz.ab_used = input_structure.ab_used;

which doesn't make it obvious that all fields are being copied,
is prone to typing errors, and gets even messier if any of the
members are structures themselves....

Besides, I don't think this was introduced in ANSI C - it
certainly exists in a number of non-ANSI C compilers I've used.

        -John Owens                     +1 703 961 7827
        Virginia Tech   Communications Network Services
        OWENSJ@VTVM1.CC.VT.EDU      OWENSJ@VTVM1.BITNET

wcs@ho95e.ATT.COM (Bill.Stewart) (01/01/88)

In article <1322@sugar.UUCP> peter@sugar.UUCP (Peter da Silva) writes:
>I would like to suggest removing a "feature" from 'C'.
>Structure assignment/passing.
	Structure assignment/passing is part of the 1980 (1979?) extensions to
	the C language, which also included enum and void.  While
	they're newer than K&R, and some early PC C compilers don't
	include them, they're an established part of the language, and
	infinite numbers of programs would brreak if they went away.
	The dp ANSI standard is correct in keeping them.

	Peter gives three objections to them:
1) If you mess up a function call (add/delete &) you've got a real mess.
	True, but this is what "lint" is good for.  Actually, it's safer
	to mess up one of these than a more normal variable, because
	the results are so ugly you'll *probably* notice them.
2) Sometimes your stack overflows if you use them.
	Only if the program was too big for the machine anyway.  While
	the ability to pass structures encourages people to put more on
	a stack than necessary, it's easy to see what they've done and
	modify it if your machine is too small.  Does your machine have
	a big data space but a 64K stack size, or are mallocs just as unsafe?
3) They don't really add anything.
	But they do - they add data hiding.  A library can provide
	types such as time_t and addr_t for data that is generated by
	some library routines and used by others, and *you* don't have
	to know what the type is.  If the variable won't fit in a
	scalar on your machine (either because it's too big, or because
	you've got a segmented architecture or perverse operating system),
	and you've disallowed structure assignment, *you* may have to
	know what the structure looks like inside.

-- 
#				Thanks;
# Bill Stewart, AT&T Bell Labs 2G218, Holmdel NJ 1-201-949-0705 ihnp4!ho95c!wcs

blm@cxsea.UUCP (Brian Matthews) (01/03/88)

46323-Bill.Stewart,2G218,x0705, (wcs@ho95e.UUCP) writes:
|In article <1322@sugar.UUCP> peter@sugar.UUCP (Peter da Silva) writes:
|>I would like to suggest removing a "feature" from 'C'.
|>Structure assignment/passing.
|	Structure assignment/passing is part of the 1980 (1979?) extensions to
|	the C language, which also included enum and void.  While
|	they're newer than K&R, and some early PC C compilers don't
|	include them, they're an established part of the language, and
|	infinite numbers of programs would brreak if they went away.
|	The dp ANSI standard is correct in keeping them.
Agreed completely.
|3) They don't really add anything.
|	But they do - they add data hiding.  A library can provide
|	types such as time_t and addr_t for data that is generated by
|	some library routines and used by others, and *you* don't have
|	to know what the type is.

This can happen whether or not structure assignment is available.  You just
have to pass pointers (perhaps to a copy) instead of the item itself, expect
pointers to be returned (or pass a pointer to an item to be filled in), and use
memcpy or bcopy to make copies of the item.  Structure assignment adds to the
"cleanness" of the language (you can pass and assign any scalar data type),
makes copying structures slightly more efficient timewise (inline copy instead
of function call.  Of course this will increase the size the code), but doesn't
add any data hiding capabilities that weren't already there.

-- 
Brian L. Matthews                               "A power tool is not a toy.
...{mnetor,uw-beaver!ssc-vax}!cxsea!blm          Unix is a power tool."
+1 206 251 6811
Computer X Inc. - a division of Motorola New Enterprises

chip@ateng.UUCP (Chip Salzenberg) (01/03/88)

In article <572@ambush.UUCP> kimcm@ambush.UUCP writes:
> [concerning structure assignment and structures as function arguments]
>
> Although I agree that it is a nice feature - but dangerous on some systems:
>
>	1) Forget the & when passing a pointer blows your program.

Forget an ampersand almost anywhere in C and your program goes out to lunch.

>	2) Passing of huge structures may bomb the stack on small systems.

Huge structures as local variables may bomb small stacks.

Repeat after me:    "That which does not protect you cannot hinder you."
Now the final word: "If you're _that_ concerned, lint the program first."
-- 
Chip Salzenberg                 UUCP: "{codas,uunet}!ateng!chip"
A T Engineering                 My employer's opinions are a trade secret.
    "Anything that works is better than anything that doesn't."  -- me

dag@chinet.UUCP (Daniel A. Glasser) (01/05/88)

In article <2313@cxsea.UUCP> blm@cxsea.UUCP (Brian Matthews) writes:
[ stuff about structure assignment and data hiding deleted ]
>This can happen whether or not structure assignment is available.  You just
>have to pass pointers (perhaps to a copy) instead of the item itself, expect
>pointers to be returned (or pass a pointer to an item to be filled in), and use
>memcpy or bcopy to make copies of the item.  Structure assignment adds to the
>"cleanness" of the language (you can pass and assign any scalar data type),
>makes copying structures slightly more efficient timewise (inline copy instead
>of function call.  Of course this will increase the size the code), but doesn't
>add any data hiding capabilities that weren't already there.
>
>-- 
>Brian L. Matthews                               "A power tool is not a toy.
>...{mnetor,uw-beaver!ssc-vax}!cxsea!blm          Unix is a power tool."
>+1 206 251 6811
>Computer X Inc. - a division of Motorola New Enterprises

Actually, using pointers instead of structure assignment/passing
in information hiding is not a solution, since after the assignment
the original copy might be changed by another routine and/or the
hidden type might be a member of a structure that is written to a
file and then read.  If a pointer is used, the referenced data must
be written to the file, some file pointer (potentially non-compatible
in size to a memory pointer (ie. PDP-11) stored in somehow and then
the two must be read back into memory and the pointer must be adjusted.
This, though possible, is not something that the beginning programmer
will want to be faced with or the experienced programmer burdened with.

I agree that structure assignment/passing is here to stay.  Although
compilers on the market at this time do not support this, most do.
This does put a burden on the compiler vendor, but not on the user
of the compiler.  The "missing &" problem is a common programming
error, but so is expecting sizeof(char *) == int, and both produce
lots of problems for those who are not expecting them.  The ANSI
function prototyping catches most of these problems, and compilers
that don't support prototyping need not support structure passing,
since they aren't ANSI conforming anyway.
-- 
					Daniel A. Glasser
					...!ihnp4!chinet!dag
					...!ihnp4!mwc!dag
					...!ihnp4!mwc!gorgon!dag
	One of those things that goes "BUMP!!! (ouch!)" in the night.

peter@sugar.UUCP (Peter da Silva) (01/06/88)

In article <7573@alice.UUCP>, ark@alice.UUCP writes:
> In article <1322@sugar.UUCP>, peter@sugar.UUCP writes:
> > I would like to suggest removing a "feature" from 'C'.

> > Structure assignment/passing.

> That would break a lot of programs, including
> C programs generated by the C++ compiler.

Now *that's* a good reason. It would break programs. Always a good reason not
change something. I withdraw the request.

OK, how about this... either get lint to flag it, or have an option for
the compiler to flag it...

#pragma religion(on)
I still think that it's against the spirit of 'C' to allow for passing or
assignment of anything that's not a first-class object.
#pragma religion(off)

Yeh, Peter, what about function pointers?

Oh shut up.
-- 
-- Peter da Silva  `-_-'  ...!hoptoad!academ!uhnix1!sugar!peter
-- Disclaimer: These U aren't mere opinions... these are *values*.

peter@sugar.UUCP (Peter da Silva) (01/07/88)

In article <1942@ho95e.ATT.COM>, wcs@ho95e.ATT.COM (Bill.Stewart) writes:
A bit about how taking this stuff out would break programs. I agree, so
it's too late to go back... let's go forward.

> 1) If you mess up a function call (add/delete &) you've got a real mess.
> 	True, but this is what "lint" is good for.  Actually, it's safer
> 	to mess up one of these than a more normal variable, because
> 	the results are so ugly you'll *probably* notice them.

Yes, the usual result on anything but a good protected operating system like
UNIX is a complete system crash.

> 2) Sometimes your stack overflows if you use them.
> 	Only if the program was too big for the machine anyway.  While
> 	the ability to pass structures encourages people to put more on
> 	a stack than necessary, it's easy to see what they've done and
> 	modify it if your machine is too small.  Does your machine have
> 	a big data space but a 64K stack size, or are mallocs just as unsafe?

It's sad but true that personal computers don't usually have automatically
expanded stack frames. You need hardware that can recover from page faults
to implement this... in fact there exist micro-based UNIX boxes that don't
give you this ability.  My machine has 4.5 megabytes of RAM in it, but I have
to keep in mind that if I go over 4K of stack I have to take special
precautions like increasing the stack size dynamically or telling the machine
to increase its default stack size.

> 3) They don't really add anything.
> 	But they do - they add data hiding.  A library can provide
> 	types such as time_t and addr_t for data that is generated by
> 	some library routines and used by others, and *you* don't have
> 	to know what the type is.  If the variable won't fit in a
> 	scalar on your machine (either because it's too big, or because
> 	you've got a segmented architecture or perverse operating system),
> 	and you've disallowed structure assignment, *you* may have to
> 	know what the structure looks like inside.

If you want to do *anything* but pass these values around or assign them you
still have to know what they look like. Ah, you say, you can always call
a library routine to compare them... but you can also call a library routine
to copy them and pass pointers. IF you're going to have structure assignment
and passing, you should also define "(time_t) < (time_t)". It's tricky, isn't
it? 

But if you're going to do a job, you should do it right.

So, what's the point? The point is that:

	(1) 'C' is not isomorphic to UNIX 'C'.
	(2) If you're not going to deal with X as a first-class object in
	    the language, don't make half efforts.
-- 
-- Peter da Silva  `-_-'  ...!hoptoad!academ!uhnix1!sugar!peter
-- Disclaimer: These U aren't mere opinions... these are *values*.

peter@sugar.UUCP (Peter da Silva) (01/07/88)

In article <144@ateng.UUCP>, chip@ateng.UUCP (Chip Salzenberg) writes:
> In article <572@ambush.UUCP> kimcm@ambush.UUCP writes:
> > [concerning structure assignment and structures as function arguments]

> > Although I agree that it is a nice feature - but dangerous on some systems:

> >	1) Forget the & when passing a pointer blows your program.

> Forget an ampersand almost anywhere in C and your program goes out to lunch.

Forget an ampersand almost anywhere else in 'C' and my compiler tells me
I'm mixing integers and pointers, or structures and pointers, or whatever
else I might be mixing.

> Now the final word: "If you're _that_ concerned, lint the program first."

If I *had* lint, I would. Instead I have a compiler that does a very good
job of type checking where it can. Thanks to structure passing, this is one
place it hasn't a hope in hell of protecting me.
-- 
-- Peter da Silva  `-_-'  ...!hoptoad!academ!uhnix1!sugar!peter
-- Disclaimer: These U aren't mere opinions... these are *values*.

tainter@ihlpg.ATT.COM (Tainter) (01/12/88)

In article <1373@sugar.UUCP>, peter@sugar.UUCP (Peter da Silva) writes:
>                                 IF you're going to have structure assignment
> and passing, you should also define "(time_t) < (time_t)". It's tricky, isn't
> it? 
> -- Peter da Silva  `-_-'  ...!hoptoad!academ!uhnix1!sugar!peter

I have seen this repeatedly, and it is starting to bother me.
I think if you are going to have structure assingment you should have
structure comparison for equality (and non equality).  This IN NO WAY
requires the definition of order (i.e. <, > comparisons).  Anyone with
mathematic training beyond basic algebra should have no problem with this.
Why should all structures form fully ordered sets?

Analogy:  cartesian coordinates for points in 2-D real space
Here each coordinate has a "natural" order inherited from its fully ordered
domain, but the set of all coordinates has no such "natural" order.

Note:  Pascal defines structure assignment and equality comparison without
defining full order.  Note:  It is trivial to define full order by the way.
One just states that the order of declaration of fields defines significance.
Since all underlying types are fully ordered composed types can have such an
arbitrary order imposed on them.

A final point, the argument that structure comparison can't be done because
of wholes is specious.  The compiler need only expand it to a field by field
comparison.  SO WHAT if it doesn't gain in performance, that isn't the point,
the goal is to get a fully defined structure support.

--j.a.tainter

--j.a.tainter

--j.a.tainter

woods@ihlpe.ATT.COM (Swan) (01/13/88)

In article <4604@ihlpg.ATT.COM> tainter@ihlpg.ATT.COM (Tainter) writes:
>
>I think if you are going to have structure assingment you should have
>structure comparison for equality (and non equality).  This IN NO WAY
>requires the definition of order (i.e. <, > comparisons).  Anyone with
>mathematic training beyond basic algebra should have no problem with this.
>Why should all structures form fully ordered sets?
>--j.a.tainter

The problem is that the compiler cannot be sure how many bytes in the
structures to compare for [in]equality.  The programmer may be in for a big
surprise if you naively assume that the compiler should compare every byte.
Take the following code segment:

struct wierd {
   int   a;
   char  b[20];
}  x, y;
...
main()
{
   char  *whocares = "Whoops!";
...
  /* Make .a elements equal: */
   x.a = y.a = 1;

   /* Scribble into x.b[0] thru x.b[13]: */
   strcpy(x.b,"Bunch of junk");
   /* Now x.b[0]='B', x.b[1]='u', ... x.b[13]='\0' */

   /* Make .b elements "equal?": */
   strcpy(x.b,whocares);    /* Write into x.b[0] thru x.b[7] */
   strcpy(y.b,whocares);    /* Write into y.b[0] thru y.b[7] */

   if (x == y)
      /* it would never get here! */
...

The reason that x is not equal to y is that x.b[8] still contains the ' ', and
x.b[9] still contains 'j', and so on from the first strcpy into it, while
y.b[8] contains whatever it was initialized to (perhaps '\0') and so on.

While it is definitely not impossible for a compiler writer to make a
structure comparitor (I think), one wonders about the practicality of it,
unless all programmers started clearing every byte of any character array in
the structures before reusing them (yuck to the sixth power).  Just to get
structure comparisons??

[One could just as easily add the following code to the above to make it
work:

#define  wierd_EQ(m,n)  ((m).a == (n).a && strcmp((m).b,(n).b) == 0)
/*       ^^^^^ name of the structure tag, if any (give it one!) */

Then use:    if (wierd_EQ(x,y))  or  if (! wierd_EQ(x,y))
in place of: if (x == y)         or  if (x != y)

There would be a similar ..._EQ macro for each structure type.  Just an idea,
anyway.]

WooDS  (Warren D. Swan)

ok@quintus.UUCP (Richard A. O'Keefe) (01/13/88)

In article <4604@ihlpg.ATT.COM>, tainter@ihlpg.ATT.COM (Tainter) writes:
> I think if you are going to have structure assignment you should have
> structure comparison for equality (and non equality).

The programming language I use most imposes a total order on all data,
and it is extremely useful.  On the other hand, it is quite wrong if
the programmer is trying to think in abstract data-type terms.  There
may be concretely distinct records which represent the same abstract
value.  (Consider two stacks with the same active elements, but with
different 'junk' elements which abstractly don't exist.)
There are two objections which are particularly relevant to C:

(1) Two records may be absolutely identical, but that does not mean that
    they should be regarded as the same.  For example, suppose I have
	
    void p(FILE *f)
	{
	    FILE g;		/* This is legal */
	    FILE *h;

	    g = *f;		/* so is this */
	    assert(g == f);	/* This isn't */
	    putc('a', f);
	    assert(g != f);	/* Illegal, but would succeed if legal */
	}

(2) In order to make structure equality work, you need equality for
    all the standard types *and* type constructors.  In particular,
    you need 'union' equality too, because you can have a 'union'
    inside a 'struct'.  But since C's unions are untagged, how can
    you tell which comparison to use?  Exempli gratia:

    void q()
	{
	    struct { union { float f; long i; } pun; } x, y;

	    assert(sizeof x.pun.f == sizeof y.pun.i);
	    x.pun.i = 0;	/* 0 and 0.0 are usually identical, but */
	    y.pun.f = -0.0;	/* is not the same bit pattern as 0.0 */
	    assert(x == y);	/* should this succeed? */
	}			/* yes if float comparison, no if int */

Since we can't do it, it can't be the case that we should do it.

jpn@teddy.UUCP (John P. Nelson) (01/13/88)

>Forget an ampersand almost anywhere else in 'C' and my compiler tells me...
>
>If I *had* lint, I would. Instead I have a compiler that does a very good
>job of type checking where it can. Thanks to structure passing, this is one
>place it hasn't a hope in hell of protecting me.

This was a discussion of the ANSI C standard, wasn't it?  (and whether
structure-passing should be part of the standard.)  If you've GOT an
ANSI conforming compiler, just use function prototypes, and your problem
is solved!  Type mismatches can't occur in function calls anymore!

 - john nelson