1================= 2STYLE OF THE CODE 3================= 4 5 Unfortunatly the style is not homogeneous throughout the program!!! 6 This problem is connected with the long life of this code and with my mind 7 which changes with experience. 8 9 10NAMING CONVENTIONS 11------------------ 12 13 Names are choosen differently for different entities in the code (types, 14 instances, macros). In particular, 15 16 InThisWay --> types 17 in_this_way --> instances 18 a, b, c, .. --> local instances (counters, and other instances which are 19 defined and used within few lines of code) 20 In_This_Way --> functions 21 IN_THIS_WAY --> macros 22 23 Names for functions usually start with a prefix. Typically, if the function 24 is a method of the object ``TheObject``, then ``TheObject_`` should be the 25 prefix. For example, ``TheObject_Do_Something``. If the function is a 26 standalone function, then it should still have a prefix which suggests in 27 which file the function may be defined. For example: 'Cmp_Operator_New' may 28 be defined in the file 'cmp.c'. Whenever a symbol is supposed to be used from 29 outside the library, it should start with the prefix ``Box``. For example: 30 ``BoxType``, ``box_instance``, ``Box_Do_Something`` or ``BOX_DO_SOMETHING`` 31 (for types, instances, functions and macros, respectively). Static functions 32 use the prefix My_ to denote they are defined in the same file. In principle, 33 one should do the same for static variables, but one should try to avoid 34 using static variables unless it is really necessary to use them, which means 35 one should never use them (even if, presently, this rule is not strictly 36 followed in the code. Mainly, for messages.c, msgbase.c and lex, yacc 37 files). For locally defined typedef the same applies: ``typedef xxx 38 MyType;``. 39 40 Here is a summary of rules which may help to make the naming of library 41 entities more uniform and less arbitrary (having to go through the library to 42 rename things is not fun and may also require to change the library interface 43 too often): 44 45 * whatever goes into the standard library should be preceded by a ``Box``, 46 ``BOX`` or ``box`` prefix, to avoid clashes with names from other 47 libraries (C doesn't allow to pack things into namespaces!): 48 49 - for types: ``BoxOneType``, ``BoxAnotherType``, ... 50 51 - for methods which get ``BoxOneType`` as first argument: 52 ``BoxOneType_Do_Something``, ``BoxOneType_Do_Something_Else``. 53 54 - other functions should be named as ``Box_Do_Something``. 55 56 * In general, a function does something, right? Therefore it is advisable 57 to choose a name that contains the verb describing what it does: 58 59 - ``BoxWin_Draw_Text`` rather than ``BoxWin_Text``, ``BoxWin_Set_Font`` 60 rather than ``BoxWin_Font``. 61 62 - functions that are querying for attributes should have again a verb in 63 their name: ``Is``, ``Has`` in order of precedence: ``BoxWin_Has_Font`` 64 rather than ``BoxWin_Font``. 65 66 - a function retrieving a property or sub-object of a parent object should 67 use the verb ``Get``: ``BoxParent_Get_Size``, ``BoxParent_Get_Item``. 68 69 70TYPESETTING CONVENTIONS 71----------------------- 72 73 Use indentation length of 2 (and spaces instead of tabs), example: 74 75 while (1) { 76 printf("Nothing to print!\n"); 77 printf("Really nothing!\n"); 78 } 79 80 Lines should not exceed 79 characters. 81 82 Avoid use of C++ keywords as variable names, for example don't use 83 'bool' since it exists in C++ and will cause a clash if the code is 84 ever compiled as C++. 85 86 87LANGUAGE CONFORMANCE 88-------------------- 89 90 Our aim is to produce code which complies with the C99 standard. 91 This allows us some freedom: 92 93 * we try to declare the variables at the beginning of each scope block, 94 just to make the code more readable (it is then clear where to look for 95 variable declarations), but don't take this role to be "God's Law". 96 If we find useful to put a statement before a declaration, then we do it! 97 98 * we can use variadic macros. 99 100 101HOW WE DEAL WITH ERRORS 102----------------------- 103 104 This typedef is defined inside 'types.h': 105 106 typedef enum { 107 BOXTASK_OK = 0, /**< Function succeeded */ 108 BOXTASK_FAILURE = 1, /**< Function failed: caller needs to report error */ 109 BOXTASK_ERROR = 2 /**< Function failed: error already reported */ 110 } BoxTask; 111 112 This is how we define many functions: 113 114 /* This functions deals with a particular task and can exit with 115 * or without errors 116 */ 117 BoxTask Do_Do_Do(...) { 118 ... 119 if (...) 120 return BOXTASK_FAILURE; /* Exits in case of errors! */ 121 122 if (...) { /* Exit, but report error first! */ 123 MSG_ERROR("Error in Do_Do_Do!") 124 return BOXTASK_ERROR; 125 126 ... 127 return BOXTASK_OK; /* Operation succesfully completed! */ 128 } 129 130 Now we call this function, testing for errors: 131 132 /* Main function */ 133 int main(void) { 134 if (Do_Do_Do(...) != BOXTASK_OK) 135 fprintf(stderr, "Error!\n"); 136 } 137 138 Note that one shouldn't use such an infrastructure if it is not really 139 necessary. In other words, when an error compromises the whole execution of 140 the program, the error should not be handled in this way, but the program 141 should be halted. For example, if we cannot allocate 40 bytes to store - for 142 example - an AST node, then why should we continue at all?! If malloc fails to 143 give us 40 bytes, it is likely that the only thing we want to do is to abort 144 the execution as soon as we can. One should then use code like: 145 146 if (critical_error) { 147 MSG_FATAL("Critical error in Name_Of_Function."); 148 assert(0); 149 return; /* if needed to make the C compiler happy, even if these days 150 gcc can cope well with such situation without complaining 151 for execution reaching end of function without returning... 152 */ 153 } 154 155 (Note that in the aforementioned example of allocation you may want to use 156 BoxMem_Safe_Alloc, which aborts automatically on failure). 157 You can use also ``abort();`` rather than ``assert(0)``, but do not use the 158 ``exit`` function (abort allows the debugger to do its job). 159 If - on the other hand - you are allowing the user to allocate a very big 160 array, then you may be interested in handling the NULL pointer returned by 161 BoxMem_Alloc. 162 163 164NULL AND CASTING 165---------------- 166 167 Other than the obvious... 168 NB: remember casts are dangerous, annoying for maintenance and can cause 169 performance hits (esp. float <-> int) 170 171 * Always use NULL for pointers instead of 0. 172 For example, 173 174 While the standard says that 0 and NULL are interchangable, NULL is specific 175 to pointers and thus is more readable and allows implicit casts/errors to be 176 picked up 177 178 * You can rely on implicit (void *) casts, it's part of the standard 179 However feel free to use the void casts in areas where redundancy 180 improves the quality or readability. 181 182 * You shouldn't rely on cast from (void *) to (Object *). 183 The idea is that automatic casts should not allow an object to acquire 184 meaning. In other words, a pointer to Object is a pointer anyway, so it 185 is fine to pass it to a function requiring as argument (void *). On the 186 contrary, a pointer to void is not - in general - a pointer to Object, 187 therefore the cast should be explicit. For BoxMem_Alloc and friends, you 188 can feel free to omit the cast, to avoid redundancy (i.e. you can use 189 Object *obj = BoxMem_Alloc(sizeof(Object)) rather than 190 Object *obj = (Object *) BoxMem_Alloc(sizeof(Object)). 191 192 * Cast to (void) when you want to make it explicit on the code that you 193 want to discard the return value of a function. 194 195 Example: 196 197 int foo(void) { 198 return 5; 199 } 200 201 /* ... */ 202 203 (void) foo(); 204 205 The following is regular C: 206 207 foo(); 208 209 But one may wonder whether it is an error: why is it not using the 210 returned value? One may argue that - in general - the return value is 211 typically the reason why you call a function. 212 A (void) cast makes it explicit that you are aware that you know that the 213 function returns something, and you *WANT* to discard it. 214 This also helps when using -Wunused-value to find out whether you discarded 215 some return values without being aware of it. 216 217 218NOTES 219----- 220 221 Some other random notes: 222 223 * Never access the elements of a structure type explicitly, except for the 224 files which provide the implementation of the corresponding type. You can 225 always define a macro in the header where the structure is defined. 226 This will make interface between sources clearer. 227 228 * We are not caring much about binary compatibility of the interface: i.e. 229 types are not opaque pointers, but are defined in full in the headers we 230 install on the system with a ``make install``. Inside them we define 231 macros which pretend to be functions and can access the structure members. 232 This means that we may break binary compatility of the Box core library 233 by just reordering the elements in the datastructure. We tolerate this 234 for now. 235 236 * we are currently not caring much about the ``const`` attribute. 237 We may want to change this. 238 239 * Note that the source directory is currently named ``box`` this is to make 240 it easy to include the core headers. The idea is that one can use 241 ``#include <box/types.h>`` in his C source, and give a 242 ``-I/path/to/include/box0.2`` to the C compiler. Typically one can give 243 something like:: 244 245 cc -c -I`box -q C_INCLUDE_PATH` myext.c -o myext.o 246 247 (try ``box -q all`` to see what Box knows about itself). 248 249