home *** CD-ROM | disk | FTP | other *** search
/ ftp.cse.unsw.edu.au / 2014.06.ftp.cse.unsw.edu.au.tar / ftp.cse.unsw.edu.au / pub / doc / papers / misc / cs.toronto.edu:programming / pikestyle.doc < prev    next >
Encoding:
Text File  |  1992-10-18  |  17.5 KB  |  529 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.                  NNNNooootttteeeessss oooonnnn PPPPrrrrooooggggrrrraaaammmmmmmmiiiinnnngggg iiiinnnn CCCC
  11.  
  12.  
  13.                           Rob Pike
  14.  
  15.  
  16.  
  17.  
  18.  
  19.  
  20. _I_n_t_r_o_d_u_c_t_i_o_n
  21.  
  22.      Kernighan and Plauger's  _T_h_e  _E_l_e_m_e_n_t_s  _o_f  _P_r_o_g_r_a_m_m_i_n_g
  23. _S_t_y_l_e  was  an  important and rightly influential book.  But
  24. sometimes I feel its concise rules were taken as a  cookbook
  25. approach to good style instead of the succinct expression of
  26. a philosophy they were meant to be.  If the book claims that
  27. variable  names  should  be  chosen meaningfully, doesn't it
  28. then follow that variables whose names are small  essays  on
  29. their  use are even better?  Isn't MaximumValueUntilOverflow
  30. a better name than maxval?  I don't think so.
  31.  
  32.      What follows is a set of short essays that collectively
  33. encourage a philosophy of clarity in programming rather than
  34. giving hard rules.  I don't expect you to agree with all  of
  35. them,  because they are opinion and opinions change with the
  36. times.  But they've been accumulating in my head, if not  on
  37. paper  until now, for a long time, and are based on a lot of
  38. experience, so I hope they help you understand how  to  plan
  39. the  details of a program.  (I've yet to see a good essay on
  40. how to plan the whole thing, but  then  that's  partly  what
  41. this  course  is  about.)   If  you find them idiosyncratic,
  42. fine; if you disagree with them, fine; but if they make  you
  43. think  about why you disagree, that's better.  Under no cir-
  44. cumstances should you program the way I say to because I say
  45. to;  program  the  way  you think expresses best what you're
  46. trying to accomplish in the program.  And do so consistently
  47. and ruthlessly.
  48.  
  49.      Your comments are welcome.
  50.  
  51. _I_s_s_u_e_s _o_f _t_y_p_o_g_r_a_p_h_y
  52.  
  53.      A program is a sort of publication.  It's meant  to  be
  54. read by the programmer, another programmer (perhaps yourself
  55. a few days, weeks or years later),  and  lastly  a  machine.
  56. The  machine doesn't care how pretty the program is - if the
  57. program compiles, the machine's happy - but people  do,  and
  58. they  should.  Sometimes they care too much: pretty printers
  59. mechanically  produce   pretty   output   that   accentuates
  60. irrelevant  detail  in  the program, which is _a_s sensible _a_s
  61.  
  62.  
  63.  
  64.                      February 21, 1989
  65.  
  66.  
  67.  
  68.  
  69.  
  70.                            - 2 -
  71.  
  72.  
  73. putting all the prepositions _i_n English text _i_n  bold  font.
  74. Although  many  people  think  programs should look like the
  75. Algol-68 report (and some systems even require you  to  edit
  76. programs  in  that  style),  a clear program is not made any
  77. clearer by such presentation, and a bad program is only made
  78. laughable.
  79.  
  80.      Typographic conventions consistently held are important
  81. to  clear  presentation, of course - indentation is probably
  82. the best known and most useful example - but  when  the  ink
  83. obscures  the intent, typography has taken over.  So even if
  84. you stick with plain old typewriter-like  output,  be  cons-
  85. cious  of  typographic  silliness.   Avoid  decoration;  for
  86. instance, keep comments brief and banner-free.  Say what you
  87. want  to  say in the program, neatly and consistently.  Then
  88. move on.
  89.  
  90. _V_a_r_i_a_b_l_e _n_a_m_e_s
  91.  
  92.      Ah, variable names.  Length is not a virtue in a  name;
  93. clarity of expression _i_s.  A global variable rarely used may
  94. deserve a long name, maxphysaddr say.  An array  index  used
  95. on  every  line  of  a  loop  needn't be named any more ela-
  96. borately than i.  Saying index or elementnumber is  more  to
  97. type  (or  calls  upon  your  text  editor) and obscures the
  98. details of the computation.  When  the  variable  names  are
  99. huge,  it's harder to see what's going on.  This is partly a
  100. typographic issue; consider
  101.  
  102.         for(i=0 to 100)
  103.                 array[i]=0
  104.  
  105. _v_s.
  106.  
  107.         for(elementnumber=0 to 100)
  108.                 array[elementnumber]=0;
  109.  
  110. The problem gets worse fast with real examples.  Indices are
  111. just notation, so treat them as such.
  112.  
  113.      Pointers also require sensible notation.  np is just as
  114. mnemonic  as  nodepointer  _i_f  you consistently use a naming
  115. convention from which np means ``node  pointer''  is  easily
  116. derived.  More on this in the next essay.
  117.  
  118.      As in all other aspects of readable  programming,  con-
  119. sistency  is  important in naming.  If you call one variable
  120. maxphysaddr, don't call its cousin lowestaddress.
  121.  
  122.      Finally,   I   prefer   minimum-length   but   maximum-
  123. information  names,  and  then  let  the context fill in the
  124. rest.  Globals, for instance, typically have little  context
  125. when  they  are  used,  so their names need to be relatively
  126. evocative.      Thus     I     say     maxphysaddr      (not
  127.  
  128.  
  129.  
  130.                      February 21, 1989
  131.  
  132.  
  133.  
  134.  
  135.  
  136.                            - 3 -
  137.  
  138.  
  139. MaximumPhysicalAddress)  for  a  global variable, but np not
  140. NodePointer for a pointer locally defined and used.  This is
  141. largely a matter of taste, but taste is relevant to clarity.
  142.  
  143.      I eschew embedded  capital  letters  in  names;  to  my
  144. prose-oriented  eyes,  they are too awkward to read comfort-
  145. ably.  They jangle like bad typography.
  146.  
  147. _T_h_e _u_s_e _o_f _p_o_i_n_t_e_r_s.
  148.  
  149.      C is unusual in that it allows  pointers  to  point  to
  150. anything.  Pointers are sharp tools, and like any such tool,
  151. used well they can  be  delightfully  productive,  but  used
  152. badly they can do great damage (I sunk a wood chisel into my
  153. thumb a few days before writing this).  Pointers have a  bad
  154. reputation  in  academia,  because  they  are considered too
  155. dangerous, dirty somehow.  But I  think  they  are  powerful
  156. _n_o_t_a_t_i_o_n,  which  means  they  can help us express ourselves
  157. clearly.
  158.  
  159.      Consider: When you have a pointer to an object, it is a
  160. name  for  exactly  that  object  and no other.  That sounds
  161. trivial, but look at the following two expressions:
  162.  
  163.         np
  164.         node[i]
  165.  
  166. The first points to a node, the second  evaluates  to  (say)
  167. the  same node.  But the second form is an expression; it is
  168. not so simple.  To interpret it, we must know what node  is,
  169. what  i is, and that i and node are related by the (probably
  170. unspecified) rules  of  the  surrounding  program.   Nothing
  171. about the expression in isolation can show that i is a valid
  172. index of node, let alone the index of the element  we  want.
  173. If  i  and j and k are all indices into the node array, it's
  174. very easy to slip up, and the compiler  cannot  help.   It's
  175. particularly  easy  to  make mistakes when passing things to
  176. subroutines: a pointer is a single thing; an  array  and  an
  177. index  must  be believed to belong together in the receiving
  178. subroutine.
  179.  
  180.      An expression that evaluates to an object is inherently
  181. more subtle and error-prone than the address of that object.
  182. Correct use of pointers can simplify code:
  183.  
  184.         parent->link[i].type
  185.  
  186. _v_s.
  187.  
  188.         lp->type.
  189.  
  190. If we want the next element's type, it's
  191.  
  192.  
  193.  
  194.  
  195.  
  196.                      February 21, 1989
  197.  
  198.  
  199.  
  200.  
  201.  
  202.                            - 4 -
  203.  
  204.  
  205.  
  206.         parent->link[++i].type
  207.  
  208. or
  209.  
  210.         (++lp)->type.
  211.  
  212. i advances but the rest of the  expression  must  stay  con-
  213. stant; with pointers, there's only one thing to advance.
  214.  
  215.      Typographic considerations enter here,  too.   Stepping
  216. through structures using pointers can be much easier to read
  217. than with expressions: less ink is needed and less effort is
  218. expended  by  the compiler and computer.  A related issue is
  219. that the type of the pointer affects  how  it  can  be  used
  220. correctly,  which  allows  some  helpful  compile-time error
  221. checking that array indices  cannot  share.   Also,  if  the
  222. objects  are  structures,  their tag fields are reminders of
  223. their type, so
  224.  
  225.              np->left
  226.  
  227. is sufficiently evocative; if an array is being indexed  the
  228. array  will  have  some  well-chosen name and the expression
  229. will end up longer:
  230.  
  231.              node[i].left.
  232.  
  233. Again, the extra characters become more  irritating  as  the
  234. examples become larger.
  235.  
  236.      As a rule, if you find code  containing  many  similar,
  237. complex  expressions  that  evaluate  to  elements of a data
  238. structure, judicious use of pointers can  clear  things  up.
  239. Consider what
  240.  
  241.         if(goleft)
  242.              p->left=p->right->left;
  243.         else
  244.              p->right=p->left->right;
  245.  
  246. would look like using a compound expression  for  p.   Some-
  247. times it's worth a temporary variable (here p) or a macro to
  248. distill the calculation.
  249.  
  250. _P_r_o_c_e_d_u_r_e _n_a_m_e_s
  251.  
  252.      Procedure names should reflect what they  do;  function
  253. names  should  reflect what they _r_e_t_u_r_n.  Functions are used
  254. in expressions, often in things like if's, so they  need  to
  255. read appropriately.
  256.  
  257.         if(checksize(x))
  258.  
  259.  
  260.  
  261.  
  262.                      February 21, 1989
  263.  
  264.  
  265.  
  266.  
  267.  
  268.                            - 5 -
  269.  
  270.  
  271. is unhelpful  because  we  can't  deduce  whether  checksize
  272. returns true on error or non-error; instead
  273.  
  274.         if(validsize(x))
  275.  
  276. makes the point clear and makes a future  mistake  in  using
  277. the routine less likely.
  278.  
  279. _C_o_m_m_e_n_t_s
  280.  
  281.      A delicate matter, requiring taste  and  judgement.   I
  282. tend to err on the side of eliminating comments, for several
  283. reasons.  First, if the code is clear, and  uses  good  type
  284. names and variable names, it should explain itself.  Second,
  285. comments aren't checked by the  compiler,  so  there  is  no
  286. guarantee  they're right, especially after the code is modi-
  287. fied.  A misleading comment can be very  confusing.   Third,
  288. the issue of typography: comments clutter code.
  289.  
  290.      But I do comment sometimes.  Almost exclusively, I  use
  291. them as an introduction to what follows.  Examples: explain-
  292. ing the use of global variables and types (the one  thing  I
  293. always  comment in large programs); as an introduction to an
  294. unusual or critical procedure; or to mark off sections of  a
  295. large computation.
  296.  
  297.      There is a famously bad comment style:
  298.  
  299.         i=i+1;        /* Add one to i */
  300.  
  301. and there are worse ways to do it:
  302.  
  303.         /**********************************
  304.          *                                *
  305.          *          Add one to i          *
  306.          *                                *
  307.          **********************************/
  308.  
  309.                        i=i+1;
  310.  
  311. Don't laugh now, wait until you see it in real life.
  312.  
  313.      Avoid cute typography in comments, avoid big blocks  of
  314. comments  except  perhaps  before  vital  sections  like the
  315. declaration of the central data structure (comments on  data
  316. are  usually  much  more  helpful than on algorithms); basi-
  317. cally, avoid comments.  If your code needs a comment  to  be
  318. understood,  it would be better to rewrite it so it's easier
  319. to understand.  Which brings us to
  320.  
  321. _C_o_m_p_l_e_x_i_t_y
  322.  
  323.      Most programs are too complicated - that is, more  com-
  324. plex   than   they  need  to  be  to  solve  their  problems
  325.  
  326.  
  327.  
  328.                      February 21, 1989
  329.  
  330.  
  331.  
  332.  
  333.  
  334.                            - 6 -
  335.  
  336.  
  337. efficiently.  Why?  Mostly it's because of bad design, but I
  338. will  skip that issue here because it's a big one.  But pro-
  339. grams are often complicated at the  microscopic  level,  and
  340. that is something I can address here.
  341.  
  342.      Rule 1.  You can't tell where a  program  is  going  to
  343. spend  its time.  Bottlenecks occur in surprising places, so
  344. don't try to second guess and put  in  a  speed  hack  until
  345. you've proven that's where the bottleneck is.
  346.  
  347.      Rule 2.  Measure.  Don't tune for  speed  until  you've
  348. measured,  and  even  then don't unless one part of the code
  349. _o_v_e_r_w_h_e_l_m_s the rest.
  350.  
  351.      Rule 3.  Fancy algorithms are slow when _n is small, and
  352. _n  is  usually  small.  Fancy algorithms have big constants.
  353. Until you know that _n is frequently going to be  big,  don't
  354. get fancy.  (Even if _n does get big, use Rule 2 first.)  For
  355. example, binary trees are always faster than splay trees for
  356. workaday problems.
  357.  
  358.      Rule 4.  Fancy algorithms are buggier than simple ones,
  359. and they're much harder to implement.  Use simple algorithms
  360. as well as simple data structures.
  361.  
  362.      The following data structures are a complete  list  for
  363. almost all practical programs:
  364.  
  365.         array
  366.         linked list
  367.         hash table
  368.         binary tree
  369.  
  370. Of course, you must also be prepared to collect  these  into
  371. compound  data  structures.   For  instance,  a symbol table
  372. might be implemented as a hash table containing linked lists
  373. of arrays of characters.
  374.  
  375.      Rule 5.  Data dominates.  If you've  chosen  the  right
  376. data  structures  and  organized things well, the algorithms
  377. will almost always be self-evident.   Data  structures,  not
  378. algorithms,  are  central  to  programming.   (See Brooks p.
  379. 102.)
  380.  
  381.      Rule 6.  There is no Rule 6.
  382.  
  383. _P_r_o_g_r_a_m_m_i_n_g _w_i_t_h _d_a_t_a.
  384.  
  385.      Algorithms, or details  of  algorithms,  can  often  be
  386. encoded  compactly,  efficiently  and  expressively  as data
  387. rather than, say, as lots of if statements.  The  reason  is
  388. that  the  _c_o_m_p_l_e_x_i_t_y  of the job at hand, if it is due to a
  389. combination of independent details, _c_a_n _b_e _e_n_c_o_d_e_d.  A clas-
  390. sic  example  of  this  is  parsing tables, which encode the
  391.  
  392.  
  393.  
  394.                      February 21, 1989
  395.  
  396.  
  397.  
  398.  
  399.  
  400.                            - 7 -
  401.  
  402.  
  403. grammar of a programming language in a form interpretable by
  404. a fixed, fairly simple piece of code.  Finite state machines
  405. are particularly amenable to this form of attack, but almost
  406. any  program  that  involves  the `parsing' of some abstract
  407. sort of input into a sequence of some independent  `actions'
  408. can be constructed profitably as a data-driven algorithm.
  409.  
  410.      Perhaps the most intriguing  aspect  of  this  kind  of
  411. design  is  that  the  tables  can sometimes be generated by
  412. another program - a parser generator, in the classical case.
  413. As  a  more earthy example, if an operating system is driven
  414. by a  set  of  tables  that  connect  I/O  requests  to  the
  415. appropriate  device  drivers, the system may be `configured'
  416. by a program that reads a description of the particular dev-
  417. ices  connected  to  the  machine in question and prints the
  418. corresponding tables.
  419.  
  420.      One of the reasons data-driven programs are not common,
  421. at least among beginners, is the tyranny of Pascal.  Pascal,
  422. like its creator, believes firmly in the separation of  code
  423. and  data.  It therefore (at least in its original form) has
  424. no ability to create initialized data.  This  flies  in  the
  425. face of the theories of Turing and von Neumann, which define
  426. the basic principles of the stored-program  computer.   Code
  427. and  data  _a_r_e  the same, or at least they can be.  How else
  428. can you explain how a compiler works?  (Functional languages
  429. have a similar problem with I/O.)
  430.  
  431. _F_u_n_c_t_i_o_n _p_o_i_n_t_e_r_s
  432.  
  433.      Another  result  of  the  tyranny  of  Pascal  is  that
  434. beginners  don't  use  function  pointers.   (You can't have
  435. function-valued  variables  in  Pascal.)    Using   function
  436. pointers  to  encode complexity has some interesting proper-
  437. ties.
  438.  
  439.      Some of the complexity is passed to the routine pointed
  440. to.  The routine must obey some standard protocol - it's one
  441. of a set of routines invoked identically - but beyond  that,
  442. what  it does is its business alone.  The complexity is _d_i_s_-
  443. _t_r_i_b_u_t_e_d.
  444.  
  445.      There is this idea of a protocol, in that all functions
  446. used  similarly  must behave similarly.  This makes for easy
  447. documentation, testing, growth and even making  the  program
  448. run distributed over a network - the protocol can be encoded
  449. as remote procedure calls.
  450.  
  451.      I argue that clear use  of  function  pointers  is  the
  452. heart of object-oriented programming.  Given a set of opera-
  453. tions you want to perform on data, and a set of  data  types
  454. you  want to respond to those operations, the easiest way to
  455. put the  program  together  is  with  a  group  of  function
  456. pointers  for each type.  This, in a nutshell, defines class
  457.  
  458.  
  459.  
  460.                      February 21, 1989
  461.  
  462.  
  463.  
  464.  
  465.  
  466.                            - 8 -
  467.  
  468.  
  469. and method.  The O-O languages give you  more  of  course  -
  470. prettier  syntax, derived types and so on - but conceptually
  471. they provide little extra.
  472.  
  473.      Combining data-driven programs with  function  pointers
  474. leads  to  an astonishingly expressive way of working, a way
  475. that, in my experience, has often led to pleasant surprises.
  476. Even  without a special O-O language, you can get 90% of the
  477. benefit for no extra work and be  more  in  control  of  the
  478. result.   I  cannot  recommend  an implementation style more
  479. highly.  All the programs I have  organized  this  way  have
  480. survived  comfortably  after  much  development - far better
  481. than with less disciplined approaches.  Maybe that's it: the
  482. discipline it forces pays off handsomely in the long run.
  483.  
  484. _I_n_c_l_u_d_e _f_i_l_e_s
  485.  
  486.      Simple rule: include files should never include include
  487. files.   If  instead  they state (in comments or implicitly)
  488. what files they need to have included first, the problem  of
  489. deciding  which files to include is pushed to the user (pro-
  490. grammer) but in a way that's easy to  handle  and  that,  by
  491. construction,  avoids  multiple inclusions.  Multiple inclu-
  492. sions are a bane of systems programming.  It's not  rare  to
  493. have files included five or more times to compile a single C
  494. source file.  The Unix /usr/include/sys  stuff  is  terrible
  495. this way.
  496.  
  497.      There's a little  dance  involving  #ifdef's  that  can
  498. prevent a file being read twice, but it's usually done wrong
  499. in practice - the #ifdef's are in the file itself,  not  the
  500. file  that  includes  it.   The result is often thousands of
  501. needless lines of code passing through the lexical analyzer,
  502. which is (in good compilers) the most expensive phase.
  503.  
  504.      Just follow the simple rule.
  505.  
  506.  
  507.  
  508.  
  509.  
  510.  
  511.  
  512.  
  513.  
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.                      February 21, 1989
  527.  
  528.  
  529.