Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!rutgers!mit-eddie!uw-beaver!tektronix!teklds!copper!stevesu From: stevesu@copper.TEK.COM (Steve Summit) Newsgroups: comp.lang.c Subject: Writing readable code Message-ID: <1158@copper.TEK.COM> Date: Tue, 23-Jun-87 02:32:00 EDT Article-I.D.: copper.1158 Posted: Tue Jun 23 02:32:00 1987 Date-Received: Wed, 24-Jun-87 07:24:31 EDT References: <8286@ut-sally.UUCP> <7001@alice.UUCP> <364@sol.ARPA> <5999@brl-smoke.ARPA> <4702@columbia.UUCP> <6714@auspyr.UUCP> Organization: Tektronix Inc., Beaverton, Or. Lines: 171 In article <6714@auspyr.UUCP>, mick@auspyr.UUCP (Mick Andrew) writes: > As far as typedefs go, I fall into the "anti" camp. When supporting > unfamiliar code, the following sequences drive me crazy > > func() > { > sometype var; > } > > Hmm, search for "sometype". In an (always obscure :-) include file we find > > typedef struct s sometype; > > Ah ha, "var" is actually a structure... now where is that structure > definition... you get the idea. By using a typedef (or even in this case > a #define), the program becomes less readable. And in article <5999@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes: > > extern func_ptr_func_int getfunc ; > > The problem with this is that anyone reading your code would have to > untangle the several levels of typedef in order to determine the meaning > of this declaration, whereas with > extern int (*getfunc())(); > the meaning of the declaration is patent. This is not a particularly > complicated construct; anyone who has to read C code should learn how > type specification works in C, after which this is easy to understand. It's unfortunate that people are finding reasons to deprecate typedefs, which can be used to substantially _i_n_c_r_e_a_s_e the readability and portability of code. The two complaints above follow from the fact that typedefs, like many features of C, can be (ab)used, with devastating effect, to make code absolutely impenetrable. Many of the things being discussed on this newsgroup (including especially the bizarre ideas about enums) simply wouldn't come up if people would be content to write their programs simply and straightforwardly, instead of treating every new programming opportunity as a chance to enter the obfuscated C hall of fame. If the program you are dealing with has been conscientiously written (and yes, I know, many programs are not) then the definition for "sometype" should be in some obviously-named header file like "sometype.h", and even if it's not obvious, it should require only a few seconds with grep to find it, if you really need to know. When you come across something like extern func_ptr_func_int getfunc ; it's a safe bet, especially when you glance down at how getfunc is used, that it is a pointer to a function returning an int, unless whoever wrote it was deliberately trying to make your life miserable. A friend of mine actually objects to #define TRUE 1 #define FALSE 0 because whenever he comes across something like while(TRUE) he claims he has to go fishing around to find out how TRUE is defined. Now, if you're dealing with a mentality that would do something like #define TRUE 0 /* don't try this at home, kids */ then you've got major problems, and it wouldn't help you if that misguided individual had avoided typedefs and/or #defines. (I will admit that the examples quoted in Mick's and Doug's postings could have been written more clearly, but the problem is not with the typedefs per se. Although typedeffed structures can certainly be confusing, they can also provide a useful abstraction, especially at a library interface, where you aren't supposed to have to know what the insides of the structure look like.) There appears to be a widespread notion, a sort of overzealous application of Occam's Razor, that programs are to be judged with the wc utility, and that, for a given algorithm, the source file with the fewest characters shall be deemed best. This leads to constructions like char *p; if(p) ... which are so endlessly discussed in this newsgroup. My only complaint with K&R, which is otherwise as close to prefection as I expect to find in this industry, is that it appears to condone that sort of usage: Although this may seem cryptic at first sight, the notational convenience is considerable, and the idiom should be mastered, if for no other reason than that you will frequently see it in C programs. [1] I have no idea what "notational convenience" is, but I suspect it has to do with keeping that character count down. The right thing to try to keep down in your programs is needless complexity, by doing everything you can to make the code comprehensible to someone (including yourself) who might have to make sense of it later. The well-considered #include, #define, typedef, or even (heavens!) goto can work wonders towards improving the readability of code. Discouraging the use of these constructs only makes it harder to write clean code, and doesn't really slow down the antagonistic programmers out there who seem to think they'll be violated if anyone can penetrate their code. It seems that there are two schools of thought on this. A large body of opinion (suggested by Doug's comment that "anyone who has to read C code should learn how type specification works," holds that, for us Real Programmers, any attempt to demystify C is akin to quiche-eating. Given the current state of the "art," it is true that everyone who wants to read existing C code should learn about type specification in all its gory detail, but I wish they didn't _h_a_v_e to. Let me make some confessions. I consider myself an excellent C programmer, but: a) I still don't completely understand _a_l_l the intricate nuances of the more obscure C types. I can usually come pretty close, but for the really strange ones, like char (*b)[6], I always check myself with a mindless automaton like cdecl. Interestingly enough, the _o_n_l_y time I have to use cdecl is when I'm reading the the fascinating but artificial posers in this newsgroup; those bizarre type constructions just don't come up that often in the real programs I work with. b) I actively prefer if(p != NULL) to if(!p) I know that they are 100% equivalent as far as a correct compiler is concerned (and they are; let's not get started on that again), and I have "mastered the idiom," but the second form takes enough extra thought, and is confusing enough to the uninitiated, that it just plain isn't worth the seven characters saved. The following quote, from _T_h_e _E_l_e_m_e_n_t_s _o_f _S_t_y_l_e, explains very well what I am trying to say: The practical objection to unaccepted and oversimplified spellings is the disfavor with which they are received by the reader. They distract his attention and exhaust his patience. He reads the form "though" automatically, without thought of its needless complexity; he reads the abbreviation "tho" and mentally supplies the missing letters, at a cost of a fraction of his attention. The writer has defeated his own purpose. [2] Now, I'm sure that a lot of you disagree with this (as I said, there seem to be two camps, and mine may be the minority), so please don't flame me on the network, unless you feel you must save others from my corrupting influence. (Private flames are always welcome, and occasionally replied to.) Steve Summit stevesu@copper.tek.com References: [1] Kernighan and Ritchie, _T_h_e _C _P_r_o_g_r_a_m_m_i_n_g _L_a_n_g_u_a_g_e, p. 101 [2] Strunk and White, _T_h_e _E_l_e_m_e_n_t_s _o_f _S_t_y_l_e, Third Edition, p. 75