home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / snip9707.zip / HUNGNOTE.TXT < prev    next >
Text File  |  1997-07-05  |  24KB  |  461 lines

  1. +++Date last modified: 05-Jul-1997
  2.  
  3. ***********
  4.  
  5. Program Identifier Naming Conventions
  6.  
  7.   This monograph is intended to give you the flavor of the major ideas behind
  8. the conventions.
  9.  
  10.   When confronted with the need for a new name in a program, a good
  11. programmer will generally consider the following factors to reach a decision:
  12.  
  13.   1.  Mnemonic value - so that the programmer can remember the name.
  14.   2.  Suggestive value - so that others can read the code.
  15.   3.  "Consistency" - this is often viewed as an aesthetic idea, yet it also
  16.       has to do with the information efficiency of the program text.  Roughly
  17.       speaking, we want similar names for similar quantities.
  18.   4.  Speed of the decision - we cannot spend too much time pondering the
  19.       name of a single quantity, nor is there time for typing and editing
  20.       extremely long variable names.
  21.  
  22.   All in all, name selection can be a frustrating and time consuming subtask.
  23. Often, a name which satisfies some of the above criteria will contradict the
  24. others. Maintaining consistency can be especially difficult.
  25.  
  26.  
  27. Advantages of the Conventions
  28.  
  29.   The following naming conventions provide a very convenient framework for
  30. generating names that satisfy the above criteria. The basic idea is to name
  31. all quantities by their types. This simple statement requires considerable
  32. elaboration. (What is meant by "types"? What happens if "types" are not
  33. unique?) However, once we can agree on the framework, the benefits readily
  34. follow. The following are examples:
  35.  
  36.   1.  The names will be mnemonic in a very specific sense: if someone
  37.       remembers the type of a quantity or how it is constructed from other
  38.       types, the name will be readily apparent.
  39.   2.  The names will be suggestive as well: we will be able to map any name
  40.       into the type of the quantity, hence obtaining information about the
  41.       shape and the use of the quantity.
  42.   3.  The names will be consistent because they will have been produced by
  43.       the same rules.
  44.   4.  The decision on the name will be mechanical, thus speedy.
  45.   5.  Expressions in the program can be subjected to consistency checks that
  46.       are very similar to the "dimension" checks in physics.
  47.  
  48.  
  49. Type Calculus
  50.  
  51.   As suggested above, the concept of "type" in this context is determined by
  52. the set of operations that can be applied to a quantity.  The test for type
  53. equivalence is simple: could the same set of operations be meaningfully
  54. applied to the quantities in questions? If so, the types are thought to be
  55. the same. If there are operations which apply to a quantity in exclusion of
  56. others, the type of the quantity is different.
  57.  
  58.   The concept of "operation" is considered quite generally here; "being the
  59. subscript of array A" or "being the second parameter of procedure Position"
  60. are operations on quantity x (and "A" or "Position" as well). The point is
  61. that "integers" x and y are not of the same type if Position (x,y) is legal
  62. but Position (y,x) is nonsensical. Here we can also sense how the concepts of
  63. type and name merge: x is so named because it is an x-coordinate, and it
  64. seems that its type is also an x-coordinate. Most programmers probably would
  65. have named such a quantity x. In this instance, the conventions merely codify
  66. and clarify what has been widespread programming practice.
  67.  
  68.   Note that the above definition of type (which, incidentally, is suggested
  69. by languages such as SIMULA and Smalltalk) is a superset of the more common
  70. definition which takes only the quantity's representation into account.
  71. Naturally, if the representations of x and y are different, there will exist
  72. some operations that could be applied to x but not y, or vice versa.
  73.  
  74.   Let us not forget that we are talking about conventions which are to be
  75. used by humans for the benefit of humans. Capabilities or restrictions of the
  76. programming environment are not at issue here. The exact determination of
  77. what constitutes a "type" is not critical, either. If a quantity is
  78. incorrectly classified, we have style problem, not a bug.
  79.  
  80.  
  81. Naming Rules
  82.  
  83.   My thesis discusses in detail the following specific naming rules:
  84.  
  85.   1.  Quantities are named by their type possibly followed by a qualifier. A
  86.       convenient (and legal) punctuation is recommended to separate the type
  87.       and qualifier part of a name. (In C, we use a capital initial for the
  88.       qualifier as in rowFirst: row is the type; First is the qualifier.)
  89.   2.  Qualifiers distinguish quantities that are of the same type and that
  90.       exist within the same naming context. Note that contexts may include
  91.       the whole system, a block, a procedure, or a data structure (for
  92.       fields), depending on the programming environment. If one of the
  93.       "standard qualifiers" is applicable, it should be used. Otherwise, the
  94.       programmer can choose the qualifier. The choice should be simple to
  95.       make, because the qualifier needs to be unique only within the type and
  96.       within the scope - a set that is expected to be small in most cases. In
  97.       rare instances more than one qualifier may appear in a name.  Standard
  98.       qualifiers and their associated semantics are listed below.  An example
  99.       is worthwhile: rowLast is a type row value; that is, the last element
  100.       in an interval. The definition of "Last" states that the interval is
  101.       "closed"; i.e., a loop through the interval should include rowLast as
  102.       its last value.
  103.  
  104.   3.  Simple types are named by short tags that are chosen by the programmer.
  105.       The recommendation that the tags be small is startling to many
  106.       programmers.  The essential reason for short tags is to make the
  107.       implementation of rule 4 realistic. Other reasons are listed below.
  108.  
  109.   4.  Names of constructed types should be constructed from the names of the
  110.       constituent types. A number of standard schemes for constructing
  111.       pointer, array, and different types exist. Other constructions may be
  112.       defined as required. For example, the prefix p is used to construct
  113.       pointers.  ProwLast (prowLast) is then the name of a particular pointer
  114.       to a row type value that defines the end of a closed interval. The
  115.       standard type constructions are also listed below.
  116.  
  117.   In principle, the conventions can be enriched by new type construction
  118. schemes. However, the standard constructions proved to be sufficient in years
  119. of use. It is worth noting that the types for data structures are generally
  120. not constructed from the tags of their fields. First of all, constructions
  121. with over two components would be unwieldy. More importantly, the invariant
  122. property of data structure, the set of operations in which they participate,
  123. seems to be largely independent of the fields of the structure that determine
  124. only the representation. We all have had numerous experiences with changes in
  125. data structures that left the operations (but not the implementation of the
  126. operations) unchanged. Consequently, I recommend the use of a new tag for
  127. every new data structure. The tag with some punctuation (upper case initial
  128. or all upper case) should also be used as the structure name in the program.
  129. New tags should also be used if the constructions accumulate to the point
  130. where readability suffers.
  131.  
  132.   In my experience, tags are more difficult to choose than qualifiers. When a
  133. new tag is needed, the first impulse is to use a short descriptive common
  134. generic English term as the type name. This is almost always a mistake. One
  135. should not preempt the most useful English phrases for the provincial
  136. purposes of any given version of a given program. Chances are that the same
  137. generic term could be equally applicable to many more types in the same
  138. program. How will we know which is the one with the pretty "logical" name,
  139. and which have the more arbitrary variants typically obtained by omitting
  140. various vowels or by other disfigurement? Also, in communicating with the
  141. programmer, how do we distinguish the generic use of the common term from the
  142. reserved technical usage? By inflection? In the long run, an acronym that is
  143. not an English worked may work out the best for tags. Related types may then
  144. share some of the letters of the acronym. In speech, the acronym may be
  145. spelled out, or a pronounceable nickname may be used. When hearing the
  146. special names, the informed listener will know that the special technical
  147. meaning should be understood. Generic terms should remain free for generic
  148. usage.
  149.  
  150.   For example, a color graphics program may have a set of internal values
  151. that denote colors. What should one call the manifest value for the color
  152. red? The obvious choice (which is "wrong" here) is RED. The problem with RED
  153. is that it does not identify its type. Is it a label or a procedure that
  154. turns objects RED? Even if we know that it is a constant (because it is
  155. spelled all caps, for example), there might be several color-related types.
  156. Of which one is RED an instance? If I see a procedure defined as
  157. paint(color), may I call it RED as an argument?  Has the word RED been used
  158. for any other purpose within the program?  So we decide to find a tag for the
  159. color type and use the word Red as a qualifier.
  160.  
  161.   Note that the obvious choice for the qualifier is in fact that the
  162. "correct" one! This is because the use of qualifiers are not hampered by any
  163. of the above difficulties. Qualifiers are not "exclusive" (or rather they are
  164. exclusive only within a smaller set) so we essentially need not take into
  165. account the possibility of other uses of the term "Red." The technical use of
  166. the term will be clear to everyone when the qualifier is paired up with an
  167. obviously technical type tag. Since qualifiers (usually) do not participate
  168. in type construction, there is no inherent reason why they would need to be
  169. especially short.
  170.  
  171.   Conversely, the tag for the type of the color value should not be "color."
  172. Just consider all the other color related types that may appear in the
  173. graphics program (or in a future variant): hardware encoding of color, color
  174. map entry number, absolute pointer to color map entry, color values in
  175. alternate color mapping mode, hue-brightness-saturation triples, other color
  176. values in external interfaces; printers, plotters, interacting external
  177. software, etc.  Furthermore, the tag will have to appear in names with
  178. constructed types and qualifiers.
  179.  
  180.   A typical arbitrary choice could be "co" (pronounced see-oh). Or, if "co"
  181. was already taken, "cv", "cl", "kl", and so on. Note that the mnemonic value
  182. of the tags is just about average: not too bad, but not too good either. The
  183. conventions cannot help with creating names that are inherently mnemonic,
  184. instead they identify, compress, and contain those parts of the program that
  185. are truly individual, thus arbitrary.  The lack of inherent meaning should be
  186. compensated by ample comments whenever a new tag is introduced. This is a
  187. reasonable suggestion since the number of basic tags remains very small even
  188. in a large system.
  189.  
  190.   In conclusion, the name of our quantity would be "coRed", provided that the
  191. color type "co" is properly documented. The value of the name will show later
  192. in program segments such as the following:
  193.  
  194.       if co == coRed then *mpcopx[coRed]+=dx ...
  195.  
  196.   At a glance we can see that the variable co is compared with a quantity of
  197. its own kind; coRed is also used as a subscript to an array whose domain is
  198. of the correct type. Furthermore, as we will see, the color is mapped into a
  199. pointer to "x", which is de-referenced (by the *operator in this example) to
  200. yield an x type value, which is then incremented by a "delta x" type value.
  201. Such "dimensional analysis" does not guarantee that the program is completely
  202. free from bugs, but it does help to eliminate the most common kinds. It also
  203. lends a certain rhythm to the writing of the code: "Let's see, I have a co in
  204. hand and I need an x; do I have a mpcox? No, but there is a mpcopx that will
  205. give me a px; *px will get me the x...", and so on.
  206.  
  207.  
  208. Naming for "Writability"
  209.  
  210.   A good yardstick for choosing a name is to try to imagine that there is an
  211. extraordinary reward for two programmers if they can independently come up
  212. with the same program text for the same problem.  Both programmers know the
  213. reward, but cannot otherwise communicate.  Such an experiment would be
  214. futile, of course, for any sizable problem, but it is a neat goal. The reward
  215. of real life is that a program written by someone else, which is identical to
  216. what one's own program would have been, is extremely readable and modifiable.
  217. By the proper use of the conventions, the idea can be approached very
  218. closely, give or take a relatively few tags and possibly some qualifiers. The
  219. leverage of the tags is enormous. If they are communicated, or are agreed on
  220. beforehand, or come from a common source, the goal becomes reachable and the
  221. reward may be reaped. This makes the documentation of the tags all the more
  222. important.
  223.  
  224.   An example of such a consideration is the discretionary use of qualifiers
  225. in small scopes where a quantity's type is likely to be unique, for example
  226. in small procedures with a few parameters and locals or in data structures
  227. which typically have only a few fields.  One might prefer to attach a
  228. qualifier even to a quantity with a unique type of "writability", the ability
  229. for someone else to come up with the name without hesitation. As many
  230. textbooks point out, the "someone else" can be the same programmer sometime
  231. in the future revisiting the long forgotten code. Conclusion: do not use
  232. qualifiers when not needed, even if they seem valuable.
  233.  
  234.  
  235. Naming Rules for Procedures
  236.  
  237.   Unfortunately, the simple notion of qualified typed tags does not work well
  238. for procedure names. Some procedures do not take parameters or do not return
  239. values. The scopes of procedure names tend to be large. The following set of
  240. special rules for procedures has worked quite satisfactorily:
  241.  
  242.   1.  Distinguish procedure names from other names by punctuation, for
  243.       example by always starting with a capital letter (typed tags of other
  244.       quantities are in lower case). This alleviates the problem caused by
  245.       the large scope.
  246.   2.  Start the name with the tag of the value that is returned, if any.
  247.   3.  Express the action of the procedure in one or two words, typically
  248.       transitive verbs. The words should be punctuated for easy parsing by
  249.       the reader (a common legal method of punctuation is the use of capital
  250.       initials for every word).
  251.   4.  Append the list of tags of some or all of the formal parameters if it
  252.       seems appropriate to do so.
  253.  
  254.   The last point is contrary to the earlier remarks on data structure naming.
  255. When the parameters to a procedure are changed, typically all uses of the
  256. procedure will have to be updated. There is an opportunity during the update
  257. to change the name as well, in fact the name change can serve as a useful
  258. check that all occurrences have been found. With data structures, the
  259. addition or change of a field will not have an effect on all uses of the
  260. changed structure type. Typically, if a procedure has only one or two
  261. parameters, the inclusion of the parameter tags will really simplify the
  262. choice of procedure name.
  263.  
  264.   Some examples for procedure names are the following:
  265.  
  266. InitSy:      Takes an sy as its argument and initializes it.
  267. OpenFn:      fn is the argument. The procedure will "open" the fn.
  268.              No value is returned.
  269. FcFromBnRn:  Returns the fc corresponding to the bn,rn,pair given.
  270.              (The names cannot tell us what the types sy, fn, fc,
  271.              etc., are.)
  272.  
  273.  The following is a list of standard type constructions. (X and Y stand for
  274. arbitrary tags. According to standard punctuation the actual tags are
  275. lowercase.)
  276.  
  277. pX        pointer to X
  278. dX        difference between two instances of type X.  X + dX
  279.           is of type X.
  280. cX        count of instances of type X.
  281. mpXY      an array of Y's indexed by X.  Read as "map from X to Y."
  282. rgX       an array of X's.  read as "range X."  The indices of the array
  283.           are called:
  284. iX        indent of the array rgX.
  285. dnX       (rare) an array indexed by type X.  The elements of the array
  286.           are called:
  287. eX        (rare) element of the array dnX.
  288. grpX      a group of X's stored one after another in storage.  Used when
  289.           the X elements are of variable size and standard array indexing
  290.           would not apply.  Elements of the group must be referenced by
  291.           means other then direct indexing.  A storage allocation zone,
  292.           for example, is a grp of blocks.
  293. bX        relative offset to a type X.  This is used for field
  294.           displacements in a data structure with variable size fields.
  295.           The offset may be given in terms of bytes or words, depending
  296.           on the base pointer from which the offset is measured.
  297.  
  298.   Where it matters, quantities named mp, rg, dn, or grp are actually pointers
  299. to the structures described above.
  300.  
  301.       cbX       size of instances of X in bytes
  302.       CwX       Size of instances of X in words
  303.  
  304.   One obvious problem with the constructions is that they make the parsing of
  305. the types ambiguous. Is pfc a tag of its own or is it a pointer to an fc?
  306. Such questions (just as many others) can be answered only if one is familiar
  307. with the specific tags that are used in a program.
  308.  
  309.   The following are standard qualifiers. (The letter X stands for any type
  310. tag. Actual type tags are in lowercase.)
  311.  
  312. XFirst       the first element in an ordered set (interval) of X values.
  313. XLast        the last element in an ordered set of X values.  XLast is the
  314.              upper limit of a closed interval, hence the loop continuation
  315.              condition should be:  x<=xLast
  316. XLim         the strict upper limit of an ordered set of X values.  Loop
  317.              continuation should be:  x<xLim
  318. XMax         strict upper limit for all X values (excepting Max, Mac,
  319.              and Nil) for all other x:  x<xMax.  If x values start with
  320.              x=0, xMax is equal to the number of different x values.
  321.              The allocated length of a dnx vector, for example, will be
  322.              typically xMax.
  323. XMac         the Current (as opposed to constant or allocated) upper limit
  324.              for all x values.  If x values start with 0, xMac is the
  325.              current number of X values.  To iterate through a dnx array,
  326.              for example:
  327.                 for x=0 step 1 to xMac-1 do ... dnx[x] ...
  328.                 or
  329.                 for ix=0 step 1 to ixMac-1 do ... rgx[ix] ...
  330. XNil         a distinguished Nil value of type X.  The value may or may not
  331.              be 0 or -1.
  332. XT           temporary X.  An easy way to qualify the second quantity of a
  333.              given type in a scope.
  334.  
  335.  
  336. SOME COMMON PRIMITIVE TYPES
  337.  
  338. f    flag (boolean, logical).  If qualifier is used, it should describe the
  339.      true state of the flag.  Exception:  the constants fTrue and fFalse.
  340. w    word with arbitrary contents.
  341. ch   character, usually in ASCII text.
  342. b    byte, not necessarily holding a coded character, more akin to w.
  343.      Distinguished from the b constrictor by the capital letter of the
  344.      qualifier in immediately following.
  345. sz   pointer to first character of a zero terminated string.
  346. st   pointer to a string.  First byte is the count of characters cch.
  347. h    pp (in heap).
  348.  
  349.   The following partial example of an actual symbol table routine illustrates
  350. the use of the conventions in a "real life" situation. The purpose of this
  351. example is not to make any claims about the code itself, but to show how the
  352. conventions can help us learn about the code. In fact, some of the names in
  353. this routine are standard.
  354.  
  355.  1   #include "sy.h"
  356.  2   Extern int *rgwDic;
  357.  3   extern int bsyMac;
  358.  4   struct SY *PsySz(sz)
  359.  5   char sz[];
  360.  6      {
  361.  7      char *pch;
  362.  8      int cch;
  363.  9      struct SY *psy, *PsyCreate();
  364. 10      int *pbsy;
  365. 11      int cwSz;
  366. 12      unsigned wHash=0;
  367. 13      pch=sz;
  368. 14      while (*pch!=0
  369. 15         wHash=(wHash<<5)+(wHash>>11+*pch++;
  370. 16      cch=pch-sz;
  371. 17      pbsy=&rgbsyHash[(wHash&077777)%cwHash];
  372. 18      for (; *pbsy!=0; pbsy = &psy->bsyNext)
  373. 19         {
  374. 20         char *szSy;
  375. 21         szSy= (psy=(struct SY *)&rgwDic[*pbsy])->sz;
  376. 22         pch=sz;
  377. 23         while (*pch==*szSy++)
  378. 24            {
  379. 25            if (*pch++==0)
  380. 26               return (psy);
  381. 27            {
  382. 28         }
  383. 29      cwSz=0;
  384. 30      if (cch>=2)
  385. 31         cwSz=(cch-2/sizeof(int)+1;
  386. 32      *pbsy=(int *)(psy=PsyCreate(cwSY+cwSz))-rgwDic;
  387. 33      Zero((int *)psy,cwSY);
  388. 34      bltbyte(sz, psy->sz, cch+1);
  389. 35      return(psy);
  390. 36      }
  391.  
  392.   The tag SY is the only product specific type in this routine. The
  393. definition of SY is found in the include file sy.h (fair enough). The type
  394. name itself is in all capitals, a common convention.
  395.  
  396.   Line 2 - says that there is an array of words, which is called
  397. Dic(tionary). Remember that since Dic is a qualifier, it is named
  398. traditionally.
  399.  
  400.   Line 3 - is the offset pointing beyond the last sy (see b constructor + Mac
  401. standard qualifier.) One has to guess at this time that this is used for
  402. allocating new sy's. The "base" of the offset would also have to be guessed
  403. to be rgwDic. Actually, the name grpsy would have been better instead of
  404. rgwDic, from this local perspective. In the real program, the rgwDic area is
  405. used for a number of different purposes, hence the "neutral" name.
  406.  
  407.   Line 4 - is a procedure declaration. Procedure returns a pointer to an SY
  408. as the result. The parameter must be a zero terminated string.
  409.  
  410.   Lines 7-12 - declare quantities. The usages should be clear from the names.
  411. For example, cwSz is the number of words in some string (probably the
  412. argument), pbsy is a pointer to an offset of an sy (p constructor + b
  413. constructor). The only qualifier used here is in wHash - the hash code.
  414.  
  415.   Line 13 - pch will be a pointer to the first character of sz.
  416.  
  417.   Line 16 - cch is the count of characters (c constructor) ostensibly,
  418. in sz.
  419.  
  420.   Line 17 - cwHash is the number of words in the hash table (I would have
  421. called it ibsyMax). In a way, the qualifier on rgbsyHash could be omitted,
  422. but it helps identifying the hash table in external contexts.
  423.  
  424.   Lines 17-18 - note the opportunities for dimensional checking:
  425.  
  426.       pbsy =  rgbsy[...] follows from pX = &rgX[...]
  427.       pbsy =  psy->bsy Next follows from pX=&pY->X; or pX = &Y.X
  428.  
  429. So even the use of -> instead of . follows from local context. The p on the
  430. left hand side signals the need for the & on the right.
  431.  
  432.   Line 20 - introduces a new sz, qualified to distinguish it from the
  433. argument. The qualifier, very appropriately, is the source of the datum, Sy.
  434.  
  435.   Line 23 - given the use of szSy in this line, the name pchSy would have
  436. been a little more appropriate. No harm done, however.
  437.  
  438.   Lines 29-31 - this strange code has to do with the fact that the
  439. declaration of SY includes 2 bytes of sz, so that cwSz is really the number
  440. of words in the sz-2 bytes! This should deserve a comment or at least a
  441. qualifier M2 (minus 2) or the like. cwSY is the length of the SY structure in
  442. words. The all caps qualifier is not strictly standard, but it helps to
  443. associate the quantity with the declaration of SY, rather than with any
  444. random sy instance.
  445.  
  446.   PsyCreate is a good procedure name; PsyCreateCw would have been even
  447. better. In line 32 we can also see an example of dimensional checking: while
  448. we have a psy inside the parenthesis, we need a bsy for the left side (*pbsy
  449. =bsy!) so we subtract the "base" of the bsy from the psy
  450.  
  451.       bX + base = pX; hence:  bX = pX - base.
  452.  
  453.   In closing, it is evident that the conventions participated in making the
  454. code more correct, easier to write and easier to read.  Naming conventions
  455. cannot guarantee "good" code however, only the skill of the programmer can.
  456.  
  457. Charles Simonyi
  458. Microsoft Corporation
  459.  
  460. **************
  461.