]> git.lyx.org Git - lyx.git/blob - development/Code_rules/Rules
7e7aaecf52aab61c5e7424d66de59826ba0600d1
[lyx.git] / development / Code_rules / Rules
1 Rules for the code in LyX
2 -------------------------
3 [updated from the C++STYLE distrubuted with the GNU C++ Standard]
4
5 The aim of this file is to serve as a guide for the developers, to aid us to
6 get clean and uniform code. This document is still uncomplete.
7
8 We really like to have new developers joining the LyX Project. However
9 since we have had problems in the past with developers leaving the
10 project and their contributed code in a far from perfect state. Most
11 of this happened before that we really became aware of these issues,
12 but still, we don't want it to happen again. So we have put together
13 some guidelines and rules for the developers.
14
15 General
16 -------
17
18 These guidelines should save us a lot of work while cleaning up the code and 
19 help us to have quality code. LyX has been haunted by problems coming from 
20 unfinished projects by people who have left the team. Those problems will 
21 hopefully disappear if the code is easy to hand over to somebody else.
22
23 In general, if you want to contribute to the main source, we expect at least 
24 that you:
25
26 - the most important rule first: kiss (keep it simple stupid), always
27   use a simple implementation in favour of a more complicated one.
28   This eases maintenence a lot.
29 - write good C++ code: Readable, well commented and taking advantage of the 
30   OO model. Follow the formatting guidelines. See Formatting.
31 - adapt the code to the structures already existing in LyX, or in case that 
32   you have better ideas, discuss them on the developer's list before writing 
33   the code.
34 - take advantage of the C++ standard library. especially don't use
35   custom containers when a standard container is usable, learn to use
36   the algorithms and functors in the standard library.
37 - be aware of exceptions and write exception safe code. See Exceptions.
38 - document all variables, methods, functions, classes etc. We are
39   using the source documentation program doc++, a program that handles
40   javadoc syntax, to document sources. See Source Documentation.
41 - we have certain code constructs that we try to follow. See Code
42   Constructs.
43
44
45 Submiting Code
46 ------------------
47
48 It is implicitly understood that all patches contributed to The LyX
49 Project is under the Gnu General Public Lisence, it you have a problem
50 with that, don't contribute code.
51
52 Also please don't just pup up out of the blue with a huge patch (or
53 small) that changes something substantial in LyX. Always discuss your
54 ideas with the developers on the developers mailinglist.
55
56 When you create the patch, please use "diff -up" since we find that a
57 lot easier to read than the other diff formats. Also please do not
58 send patches that implements/fix several different things, several
59 patches is a much better option.
60
61 We also expect you to provide a ChangeLog entry with every patch, this
62 describes shortly what the patch is doing. The ChangeLog entry follows
63 this syntax:
64
65 1999-12-13  Lars Gullik Bjønnes  <larsbj@lyx.org>
66
67         * src/support/lyxstring.C (find): assert bug fixed.
68
69
70 Code Constructs
71 ---------------
72
73 We have several guidelines on code constructs, some of these exists to
74 make the code faster, others to make the code clearer. Yet others
75 exists to make us able to take advantage of the strong type checking
76 in C++.
77   
78 - Declaration of variables should wait as long as possible. The rule
79   is: "Don't declare it until you need it." In C++ there are a lot of
80   user defined types, and these can very often be expensive to
81   initialize. This rule connects to the next rule too.
82
83 - Make the scope of a variable as small as possible.
84
85 - Prefere preincrement to postincrement whenever possible.
86   Preincrement has potential of beeing faster than postincrement. Just
87   thing about the obvious implementations of pre/post-increment. This
88   rule applies to decrement too.
89
90         ++T;
91         --U;
92         -NOT-
93         T++; // wrong
94         U--; // wrong
95
96 - Try to minimize evaluation of the same code over and over. This is
97   aimed especially at loops.
98
99         Container::iterator end = large.end();
100         for (Container::iterator it = large.begin(), it != end; ++it) {
101                 ...;
102         }
103         -NOT-
104         for (Container::iterator it = large.begin();
105              it != large.end(); ++it) {
106                 ...;
107         }
108
109 - For functions and metods that returns a non-POD type T, return T
110   const instead. This gives better type checking, and will give a
111   compiler warning when temporaries are used wrongly.
112
113         T const add(...);
114         -NOT-
115         T add(...);
116
117 - Avoid using the default cases in switch statements unless you have
118   too. Use the correct type for the switch expression and let the
119   compiler ensure that all cases are exhausted. 
120
121         enum Foo {
122                 foo,
123                 bar
124         };
125         Foo f = ...;
126         switch (f) {
127         case foo: ...; break;
128         case bar: ...; break;
129         default: ...; break; // not needed and would shadow a wrong use of Foo
130         }
131
132 Exceptions
133 ----------
134
135 Even if LyX currently is not using exceptions we need to be aware of
136 them. One important thing to realize is that you often do not have to
137 use throw,try or catch to be exception safe. Let's look at the
138 different types of exceptions safety: (These are taken from Herb
139 Sutters book[ExC++]
140
141 "
142 1. Basic guarantee: Even in te presence of exceptions thrown by T or
143 other exceptions, Stack objects don't leak resources.
144         Note that this also implies that the container will be
145         destructible and usable even if an exception is thrown wile
146         performing some container operation. However, if an exception
147         is thrown, the container will be in a consistent, but not
148         necessarily predictable, state. Containers that support the
149         basic guarantee can work safely in some settings.
150
151 2. Strong guarantee: If an operation terminates because of an
152 exception, program state will remain uncanged.
153         This always implies commit-or-rollback samantics, including
154         that no references or iterators into the container be
155         invalidated if an operation fails. For example, if a Stack
156         client calls Top and then attempts a Push that fails because
157         of an exception, then the state of the Stack object must be
158         unchanged and the reference returned from the prior call to
159         Top must still be valid. For more information on there
160         guarantees, see Dave Abrahams's documentation of the SGI
161         exception-safe standard library adaption at:
162         http://www.metabyte.com/~fbp/stl/eg_contract.html 
163
164         Probably te most interesting point here is tat wen you
165         implement the basic guarantee, the strong guarantee often
166         comes for free. For example, in our Stack implementation,
167         alost everything we did was needed to satisfy just the basic
168         guarantee -- and wath's presented above very nearly satisfires
169         the strong guarantee, with little of no extra work. Not half
170         bad, considering all the trouble we went to.
171
172         In addition to tese two guarantees, there is one more
173         guarantee that certain functions must provide in order to make
174         overall exception safety possible: 
175
176 3. Nothrow guarantee: Te function will not emit an exception under any
177    circumstances.
178         Overall exception safety isn't possible unless certain
179         functions are guaranteed not to throw. In particualr, we've
180         seen that this is true for destructors; later in tis
181         miniseries, we'll see that it's also needed in certain helper
182         functions, such as Swap(). 
183 "
184
185 For all cases where we might be able to write exception safe functions
186 without using try,throw or catch we should do so. In particular we
187 should look over all destructors to ensure that they are as exception
188 safe at possible.
189
190 Later when more compiler support exceptions sufficiently well we will
191 begin using them too. One reason for this is that the C++ standard
192 library actually requires exceptions, e.g. "new" will throw
193 bad_allocation if the requested memory is not available.
194
195
196 Formatting
197 ----------
198
199 * Only one delaration on each line.
200         int a;
201         int b;
202         -NOT-
203         int a, b; // wrong
204   This is especially important when initialization is done at the same
205   time:
206         string a("Lars");
207         string b("Gullik");
208         -NOT-
209         string a("Lars"), b("Gullik"); // wrong
210
211 * Pointers and references
212         char * p = "flop";
213         char & c = *p;
214         -NOT-
215         char *p = "flop"; // wrong
216         char &c = *p;     // wrong
217
218   Some time ago we had a huge discusion on this subject and after
219   convincing argumentation from Asger this is what we decided. Also note
220   that we will have:
221         char const * p;
222         -NOT-
223         const char * p; // wrong
224
225 * Operator names and parentheses
226         operator==(type)
227         -NOT-
228         operator == (type)  // wrong
229
230   The == is part of the function name, separating it makes the
231   declaration look like an expression.
232
233 * Function names and parentheses
234         void mangle()
235         -NOT-
236         void mangle ()  // wrong
237
238 * Enumerators
239         enum {
240                 one = 1,
241                 two = 2,
242                 three = 3
243         };
244         -NOT-
245         enum { one = 1, two = 2, three 3 }; // wrong
246
247 * Naming rules for classes
248
249   - Use descriptive but simple and short names. For stuff specific to LyX
250     use LyX as prefix. Some modules, like mathed or spellchecker, could have
251     other prefixes.
252     [I am not so sure about the LyX prefix]
253
254   - Class names are usually capitalized, and function names lowercased.
255     Enums are named like Classes, enum values in CAPS.
256
257   - Long variables are named like thisLongVariableName.
258
259   New types are capitalized, so this goes for typedefs,classes,structs
260   and enums.
261
262 * Formatting
263
264   - Please adapt the formatting of your code to the setting in LyX in that
265     particular file. Lars and Asger are slowly, but surely moving the source 
266     towards Linux kernel style formatting, aka K&R style. We suggest that you 
267     also do this, but this is NOT something that has been decided generally.
268
269
270 * Use existing structures
271
272   - Use string whereever possible. LyX will someday move to Unicode, and
273     that will be easy if everybody uses string now.
274
275   - Check out the filename and path tools in filetools.h
276
277   - Check out the string tools in lstring.h, and the SubString class
278     and the regex class.
279
280   - Use the DebugStream class to report errors and messages using
281     the lyxerr instantation.
282
283   [add description of other existing structures]
284
285
286 * Declarations
287   
288   - Use this order for the access sections of your class: public,
289     protected, private. The public section is interesting for every
290     user of the class. The private section is only of interest for the
291     implementors of the class (you). [Obvously not true since this is
292     for developers, and we do not want one developer only to be able to
293     read and understand the implementation of class internals. Lgb]
294   
295   - Avoid to declare global objects in the declaration file of the class. 
296     If the same variable is used for all object, use a static member.
297
298   - Avoid global or static variables. An exception to this rule is 
299     very private stuff like the math stack.
300
301   - Use the const keyword like this: char const * instead of const char *
302     because this is more logical.
303
304
305 * Documentation
306
307   - The documentation is generated from the header files.
308   - You document for the other developers, not for yourself.
309   - You should document what the funtion do, not the implementation.
310   - in the .C files you document the implementation.
311   - Single line description (///), multiple lines description (/** ... */)
312   - You make the documentation by doing "make srcdoc" in the root,
313     and then you'll find HTML in the srcdoc/ directory. Read with
314     Netscape for best results.
315
316
317 * NAMING RULES FOR USER-COMMANDS
318    
319   Here's the set of rules to apply when a new command name is introduced:
320  
321   1) Use the object.event order. That is, use `word-forward' instead of 
322      `forward-word'.
323   2) Don't introduce an alias for an already named object. Same for events.
324   3) Forward movement or focus is called `forward' (not `right').
325   4) Backward movement or focus is called `backward' (not `left').
326   5) Upward movement of focus is called `up'.
327   6) Downward movement is called `down'.
328   7) The begin of an object is called `begin' (not `start').
329   8) The end of an object is called `end'.
330
331
332 * Using external GUI constructors (XForms fdesign)
333
334   - Fdesign generated files should not be changed at all. The only changes
335     needed are gettext, compability with 0.88 or when you have made your own
336     xforms objects and have just a dummy in the .fd file in place of your
337     own. In case you have to change the generated files for any of the
338     reasons above, you should provide a patch against the clean generated
339     file. Your callbacks must be in a separate file.
340
341  *************************************************************
342
343  How to create class interfaces.
344  (a.k.a How Non-Member Functions Improve Encapsulation)
345  ======================================================
346
347         I recently read an article by Scott Meyers in C/C++ Users
348 Journal (Vol.18,No.2), where he makes a strong case on how non-member
349 functions makes classes more encapsulated, not less. Just to skipping
350 to the core of this provides us with the following algorithm for
351 deciding what kind of function to add to a class interface:
352
353         - We need to add a function f to the class C's API.
354
355         if (f needs to be virtual)
356                 make f a member function of C;
357         else if (f is operator>> or operator<<) {
358                 make f a non-member funtion;
359                 if (f needs access to non-public members of C)
360                         make f a friend of C;
361         } else if (f needs type conversions on its left-most argument) {
362                 make f a non-member function;
363                 if (f needs access to non-public members of C)
364                         make f a friend of C;
365         } else if (f can be implemented via C's public interface)
366                 make f a non-member function;
367         else
368                 make f a member function of C;
369  
370 Unfortunately, to make the best use of this kind of Class API's we
371 need namespaces. As soon as Jean-Marc stop using gcc 2.8 and other
372 compilers seem more or less up to date on namespaces we will begin to
373 use them. _BUT_ we should begin to use the above algoritm ASAP. We
374 should also go through old code and apply this algorithm to the
375 existing member functions. That will help maintainability in the
376 future.
377
378 (I'll fill in more from Scott Meyers article when time allows.)
379
380 References
381 ----------
382
383 [ExC++] Sutter, Herb. Exceptional C++: 47 engineering puzzles,
384         programming problems, and solutions. ISBN 0-201-61562-2