[net.unix] typedefs, functions returning pointers to functions

stevesu@azure.UUCP (Steve Summit) (12/22/83)

What in the world do people have against typedefs?  They make
code quite a bit more readable and portable.  I was glad when
people started pointing them out to me.  (So what if the
implementation is a bit baroque?  It has to be.)

getroutine, the module of mine that started this whole
discussion, used to start out

	int (*getroutine(name, table))()

which is rather unreadable and also violates the convention that
routine names should begin in column 1 so they can be easily
found with an editor.  (Writing

	int (*
	getroutine(name, table))()

looks pretty weird, with the unmatched parentheses.)  getroutine
now starts out

	FUNCPTR
	getroutine(name, table)

which is quite a bit more readable.  (FUNCPTR, for those of you
who have somehow missed the fourteen articles on the subject, is
defined as

	typedef int (*FUNCPTR)();

The new type FUNCPTR also cleared up another problem:  getroutine
has two distinct error returns, NULL and -1.  (I'm banking on the
fact that -1 will probably never be a valid pointer.  If you want
to flame about this, flame about signal(2) too.)  Although the 11
compilers would let me say

	return(-1);

the vax compilers (correctly) generate an "incompatible
integer/pointer" warning.  I'm not sure what the proper cast
would be; it would probably be something horrendous like

	return((int *())(-1))

Again, it's not at all obvious what that means.  The typedef
version is clear:

	return((FUNCPTR)(-1));

Rob Warnock relates a similar function pointer declaration
problem which he "finally solved using typedefs, but wasn't
happy, since there seemed something inelegant about that."  He
then demonstrates (somewhat proudly, it seems) a program which
"does it WITHOUT typedefs" although he admits that "the typedef
version is easier to read, and was what was used in production."

	Read carefully! The line that starts "struct..."
	is actually declaring "state".

	struct foo	{ struct foo (*(*dummy)())[];	} (*state)[];

Note that the "line that starts 'struct...'" does not even have a
comment!  If came across a line like that in a piece of code I
was trying to modify or debug, I'd weep.  Then I'd curse the
programmer who had the gall to write it.  (Sorry to pick on you,
Rob, but there's an important point here.)  C programmers have a
bad reputation for writing cryptic, unreadable, hackish code. 
Examples like this make that reputation well-deserved. 
PARTICULARLY when the compiler generates identical instructions
(as Rob assures us it does) PLEASE PLEASE write readable code! 
Everyone will benefit (except maybe you, if you happen to be on a
power trip trying to confuse everybody else.)

I always write

	while(*p++ != '\0')

instead of

	while(*p++)

even though I know they do the same thing.  Sure, the "!= '\0'"
isn't strictly necessary in this case, but I always have to look
twice at lines like the second one.  The first one is more
natural.  Only if you blindly equate "elegant" with "minimal" is
the second one more "elegant."

I once had points taken off on a programming assignment for
writing something like

	if(a == b) return(TRUE);
	else return(FALSE);

The grader said I should have "more succinctly" said

	return(a == b);

I realize now that he was wrong, and I wish I'd realized it then,
and called him on it.  He was obviously a fully indoctrinated
member of the "hacks are beautiful" school.  Those two fragments
do do the same thing, and this is a case where the second one
might even generate slightly more efficient code.  But I have to
look at something like "return(a == b)" twice or even three times
to convince myself that it's identical to what I conceptualize as
"if a equals b it's true, otherwise it's not."  Why make things
difficult?  I know the idiom, and it still gets in my way. 
Someone who had never seen it might never figure out what it did.
(I remember spending fifteen minutes explaining to a friend in an
introductory programming class how return(a == b) worked.)

Sorry this got so long.  Cryptic, hackish code is just so ugly,
while clean, modular, readable code can be truly elegant.

                                         Steve Summit
                                         tektronix!tekmdp!stevesu

barmar@mit-eddie.UUCP (Barry Margolin) (12/29/83)

While I agree with Steve Summit's message in general, I have to take
exception with him on one of his points and side with the programming
teacher.  I find nothing cryptic in

	return (a == b)

It merely means "return whether a and b are equal".  Were I a
programming teacher I wouldn't go so far as to take points of for saying

	if (a == b) return (TRUE);
	else return (FALSE);

I suppose that some theory of good programming style might dictate that
conditionals should only be used in places where only conditionals are
expected, such as in the test in an "if" or "for" statement.  I don't
happen to agree with this, but I will defend to the death someone's
right to program this way.
-- 
			Barry Margolin
			ARPA: barmar@MIT-Multics
			UUCP: ..!genrad!mit-eddie!barmar