dUFLP/dHUNG Coding Standards and Conventions Version 0.7 April 17, 1992 dUFLP -- dBASE Users Function Library Project -- Coding Standards and Conventions -- Based upon the HUNGARIAN / xBase Conventions by Robert A. DiFalco. These Standards and Conventions have been defined and generally agreed upon by several of the 'regulars' on the Borland (once Ashton-Tate) Bulletin Board System (BORBBS (now defunct)), but are by no means a rigid definition. This file contains modifications to Robert DiFalco's (CIS: 71610,1705) HUNG standard for X-Base languages; it was developed by members of the Ashton-Tate/Borland Bulletin Board System to be used in a user-developed library. Several aspects of this document have been changed, as the dUFLP standards are more aimed at dBase than other programming languages, but have been only slightly modified where needed, and some duplicate definitions were removed in the variable naming practices. The original document (HUNG14.ZIP) may be found on the CompuServe dBASE Forum. The purpose of this document is to define some coding standards to be used in the library for dUFLP, Please attempt to follow these standards as closely as possible when creating Functions and Procedures to be included in this library. Thank you ... (most of the text from this point on is DiFalco's own words) --------------------------------------------------------------------------- Let me start off by stating that these are only my opinions on naming conventions for xBase programming. In my opinion these methods are extensible to C, ASM, BASIC and just about any other programming language. It looks very similar to Hungarian notation as outlined by Charles Simonyi of Microsoft Corporation. Don't be fooled, however, this is much different. I find it more intuitive and logical though that may pertain only to my thinking. These conventions take in the same factors as outlined by Charles Simonyi for creating names in a program. The factors listed below are directly quoted from his monograph. Begin quote: 1. Mnemonic value - so that the programmer can remember the name. 2. Suggestive value - so that others can read the code easily. 3. "Consistency" - this is often viewed as an aesthetic idea, yet it also has to do with the information efficiency of the program text. Roughly speaking, we want similar names for similar quantities. 4. Speed of decision- we cannot spend too much time pondering the name of a single quantity, nor is there time for typing and editing extremely long variable names. End quote: In dBase, our variable names have even a more pressing reason for short identifiers since we only have 10 characters to work with. To alleviate using needless characters, we will use lowerUpper combinations instead of dividing underscores. ===================================== Procedure/Function Naming conventions ===================================== Procedures and Functions will be heretofore called "Functions". Function names will not be "typed" as variables. As dBase in general heads towards object oriented approaches it is important to allow our Functions to return multiple types. This negates the approach of typing Functions by return variable type. Instead we will apply a "loose" set of rules to Functions. Native language functions will be in all lowercase while 3rd party or "home grown" functions (UDF or User-Defined Functions) will be mixed case beginning with a single Capital letter. ------------- UDF Name Case ------------- All User Defined Functions will be mixed case, with no underscores. The first letter will be upper case, e.g. AllTrim. 1. Functions will start with a capital letter followed by lower case letters thus distinguishing them from variables. If the Function name can be better expressed by two or three identifiers an UpperLower combination will be used rather than underscores to delimit identifiers. Consider the following Examples: ClrSet() - Sets colors SaveGets() - Saves active get list PrnScr() - Prints the screen GetPass() - Gets a password Choose() - Menu of items to "choose" from 2. Conversion Functions will start with the value they take and end with converted value separated by the number 2. Some examples would be as follows: Str2Arr() - Changes a string to an array. Hex2Dec() - Changes a Hex string into a decimal numeric. Clr2Attr() - Changes a color string to an integer attribute. Dbf2Arr() - Loads a DBF into an array. 3. Where possible, use standard qualifiers as outlined in the section dedicated to "Variable Naming Conventions". A few examples follow. cFName = HCUST->FNAME cLName = HCUST->LNAME cAddr = HCUST->ADDR nAge = HCUST->AGE lActive = HCUST->ACTIVE nBalance = HLOAN->BALANCE ( Please note that the storage operators ( "=" ) are lined up for easy reading giving a table appearance. ) 4. Where possible, express the function or procedure in less than three qualifiers ( names ). Refer to the examples given for Rule 1. 5. The keywords PROCEDURE, FUNCTION and RETURN shall be in all uppercase. FUNCTION SayStr parameters cMsg xSavClr = set( "ATTRIBUTES" ) set color to rg+/r ? cMsg set color to xSavClr RETURN "" dBASE native functions shall be typed in all lowercase to delineate them from non-native functions as in the above call to set(). ------------------ Reserved Word Case ------------------ Except for the reserved words 'FUNCTION', 'PROCEDURE', and 'RETURN', all dBASE reserved words should be lower case. ----------------------------- File Name and Field Name Case ----------------------------- All reference to DOS files (e.g. .dbf, .fmt, .frg, etc.) and field names are to be in upper case. Underscores are allowed. ------------ Case Summary ------------ all lower : built-in commands and functions mIxed, fIrst lEtTer lOWer : memvars MiXed, First LetTer UpPer : UDFs ALL UPPER : files and fields, and the commands FUNCTION, PROCEDURE, and RETURN ============================================= DBF and Field related Punctuation Conventions ============================================= There are some rules noteworthy for DBF, NDX/MDX, ALIAS and FIELD operations to delineate them from Functions and Variables. FIELD names will NOT be typed by a lowercase type identifier as with Variables. 1. Database and Index files, as well as Field names will always be expressed in capital letters. As dBase's main point of existence is the manipulation of DataFiles, this will make them stand out against variables and other qualifiers. 2. Where possible they will use the same standard qualifiers used for Variables and Functions. See the examples for Rule 3 of "Procedure/Function Naming Conventions". 3. Fields will be referenced by an ALIAS. Consider the following. HACCT->ACCNUM HCONST->PASSWORD HCONST->COMPANY 4. Variables referencing Fields will have the same name as the Field with the addition of the dHUNG type prefix. cFName = HCUST->FNAME cLName = HCUST->LNAME cAddr = HCUST->ADDR nAge = HCUST->AGE lActive = HCUST->ACTIVE nBalance = HLOAN->BALANCE ( Please note that the storage operators ( "=" ) are lined up for easy reading giving a table appearance. ) 5. With regard to DBF file names, data, index or otherwise they should all begin with a common prefix and that prefix is similar to the name. This insures that I have few naming conflicts with other systems that may reside on the computer and just about guarantees I can separate my files out if they get placed into a common subdirectory. 6. Index filenames should reflect the file that they belong to but should not attempt to indicate what the index expression is. A much cleaner routine results when index files are simply numbered. HACCTS.DBF ---> HACCTS1.NDX HACCTS2.NDX HACCTS3.NDX Internally the only information I am required to keep is the index key in an array and all indexes can be rebuilt in the order of their respective suffix number. =============================== Command Punctuation Conventions =============================== This area of my dHUNG naming conventions will probably meet with the most opposition. User Defined Commands will use descriptive names as outlined in "Procedure/Function Naming Conventions". User Defined or not, Commands will have one Rule. 1. All Commands will be typed with lower case letters. The reasons for this are simple. This will delineate commands from variables, functions and DBF elements. Consider the following examples. FUNCTION CmdExample use HCUST set index to HCUST1, HCUST2, HCUST3 cLName = "DiFalco" seek cLName HCUST->AGE = 28 HCUST->ACTIVE = .t. HCUST->LNAME = cLName close database RETURN "" ( Please take note that in replace statements we also line up the "with" portion of the command as we do storage operators. ) =========================== Variable Naming Conventions =========================== This is the heart of a well designed system. Variable names must give the most amount of information possible in its name while using the minimum number of characters possible. All memory variables (memvars) are mixed case names, consisting of 1-10 alphanumeric characters. The first character is always a lower case type prefix. Underscores are only used as scope prefixes. Memvar names should not repeat type prefix information. But memvars may have a combination of tags that will in most cases appear in this order. 1. A single lower case variable defining its type as returned by a Type() function called a "Type Prefix". 2. An Optional state called a "State Qualifier" 3. A "Standard Qualifier Tag". 4. An Optional "Pointer Reference". ------------- Type Prefixes ------------- A type prefix is the first character of a variable that represents the type the programmer intends for the variable. Below is the list of dBASE-specific type prefixes together with examples: Prefix Type Example ------ ---- ------- a Array aList c Character cFName d Date dPmtDue f Float fAngle l Logical lExitMenu m Menu mMain n Numeric nHours p Pad pOpenDbf s Screen sBackgrnd u popUp uFlds w Window wError x undefined xLookUp For temporary variables of distinct type or pointers this single prefix can be used by itself. Consider this example. n = 0 do while n < nFldMax n = n + 1 aFldName[n] = Field( n ) enddo -------------- Scope Prefixes -------------- In dBASE, a variable can be either local to a procedure or global to all procedures. This distinction is represented by the scope prefix. Variables that are global are represented by an underscore after the type prefix; variables that are local to a procedure have a null scope prefix. For example, c_DbfFile is a character variable that is global; cDbfFile would be the same variable if it was local. ------------------------- Sample "State Qualifiers" ------------------------- New - a New state Sav - a Saved state Tem - a Temporary state -------------------------------- Sample "Standard Qualifier" tags -------------------------------- Attr - Attribute Clr - Color Crs - Cursor Dbf - of or pertaining to a DBF F - First as in cFName File - Any type of file Fld - Field L - Last as in cLName Msg - Message Name - a name Ndx - of or pertaining to an Index ( or Mdx ) Rec - Record Number Ret - Return value ( lRet = .f. ) Str - String T - Top L - Left B - Bottom R - Right Row - Row Col - Column X - Row Y - Column Please note that Standard Qualifiers can be used in combinations as in the following examples. nTRow - Top Row cFName - First name cDbfFile - a Database file cNdxFile - an Index File --------------------------- Sample "Pointer References" --------------------------- 1,2,3 - State pointer references as in cSavClr1, cSavClr2, etc. Max - Strict upper limit as in nFldMax, maximum number of Fields Min - Strict lower limit as in nRecMin, minimum number of Records These lists are to serve as samples and building blocks. They can and should be added to. Lets look at a few examples of the conventions at work. This should dispel the myth that notation conventions cannot be applied to variables with a 10 character maximum length. ========================================== Poorly Designed and Well Designed Examples ========================================== WRONG RIGHT WHY -------------------------------------------------------------------------- nFldNum nFld Number is indicated by the Type Prefix making the word Num redundant and a needless use of character space. Count n n serves as a temporary count index. Count has no Type Prefix - could also be called nCount. Last_Name cLName This is one of the most horrendous mistakes. First we do not specify the variable type. Second we needlessly spell out LAST and worst of all we use up a precious character by using an underscore instead of using the UpperLower combination. SaveScreenA sSav1 No Type Prefix, needless use of characters. The SaveScreenB sSav2 alphabetical reference is allowable though I prefer SaveScreenC sSav3 to use a numeric reference. Use of 's' type prefix removes need to use Scrn or sScreen. ColorStr xClr No Type Prefix. Needless use of characters. This shows the usage of 'unknown' type with the Type Prefix 'x' (colors are character strings in specific formats, but do not require a special type). nRecNo nRec The use of "No" is redundant. PrintReset xPrnReset Also could have been shortened to cPrnRst. MessageStr cMsg These are starting to become obvious, don't you think? ====================== Standard Header Format ====================== Below is the recommended header format to be used for procedures/functions. This will allow the automated maintenance of library functions as well as documenting the routine. By using this header, it will make it possible to create a routine either in dBASE or some other software that can generate a library listing, giving the pertinent information. Please also note EoF/EoP comment at the END of the function or procedure. FUNCTION AllTrim && {ver 0.8} *-------------------------------------------------------------------------- *-- Programmer..: HazMatZak *-- Date........: 07/02/1991 *-- Notes.......: Used to remove leading and trailing blanks from *-- a string. *-- Written for.: dBASE IV, 1.1 *-- Rev. History: 05/23/1991 0.1 - Original version (CLW) *-- 06/18/1991 0.2 - Revision to modify for dHUNG *-- 06/19/1991 0.3 - Revised for ... *-- 06/24/1991 0.4 - Revised for ... *-- 06/25/1991 0.5 - Revised again by Ken Mayer *-- to give smaller header ... *-- etc. *-- Calls.......: None *-- Called by...: Any *-- Usage.......: AllTrim() *-- Example.....: ? AllTrim(" Test string ") *-- Returns.....: String to be trimmed (i.e.:"Test string") *-- Parameters..: cArg = String to be trimmed *-------------------------------------------------------------------------- parameters cArg RETURN ltrim(rtrim(cArg)) *-- EoF: AllTrim() ------------- Documentation ------------- It is always a good idea to document code -- never assume you will be the only programmer to read your code. If it is being posted on CompuServe, a lot of people may download it. If they wish to understand what you are doing, or use just portions of your code, it is very useful to explain in at least some detail what your program/function/procedure is doing. We are not going to suggest more than attempt to make the documentation neat, concise, and to the point (don't ramble). ---------------------- dHUNG Revision History ---------------------- 1991-05-23 0.1 Initial revision (clw) 1991-06-18 0.2 Revision after notations vote (clw) 1991-06-19 0.3 Memvars, Files, Fields, UDFs, Case Summary (HazMatZak) 1991-08-20 0.4 Added official header example (clw) 1991-08-26 0.5 Combined original DiFalco document (HUNG14.ZIP) with CLW's dHUNG documentation, and the header information (KenMayer). 1991-08-30 0.6 Minor corrections to make this dBASE specific (KenMayer). 1992-04-16 0.7 Minor corrections to make this 'Politically Correct'. (Ken Mayer (KenMayer))