X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=development%2FCode_rules%2FRules;h=2212a6140b025464f648328a8aa073d6c61eee05;hb=d03113557b69430d23ff7ae8b2e7d71e249df4ec;hp=f065a90078b139d1df02750453233fe7ec26ca11;hpb=27de1486ca34aaad446adb798d71a77d6f6304da;p=lyx.git diff --git a/development/Code_rules/Rules b/development/Code_rules/Rules index f065a90078..2212a6140b 100644 --- a/development/Code_rules/Rules +++ b/development/Code_rules/Rules @@ -1,91 +1,350 @@ Rules for the code in LyX ------------------------- +[updated from the C++STYLE distributed with the GNU C++ Standard] The aim of this file is to serve as a guide for the developers, to aid us to -get clean and uniform code. Still uncomplete. +get clean and uniform code. This document is still incomplete. -In general, if you want to contribute to the main source, we expect at least -that you: +We really like to have new developers joining the LyX Project. However, +we have had problems in the past with developers leaving the +project and their contributed code in a far from perfect state. Most +of this happened before we really became aware of these issues, +but still, we don't want it to happen again. So we have put together +some guidelines and rules for the developers. -- write good C++ code: Readable, well commented and taking advantage of the - OO model. -- adapt the code to the structures already existing in LyX, or in case that - you have better ideas, discuss them on the developer's list before writing - the code. +General +------- -These guidelines should save us a lot of work while cleaning up the code and -help us to have quality code. LyX has been haunted by problems coming from -unfinished projects by people who have left the team. Those problems will +These guidelines should save us a lot of work while cleaning up the code and +help us to have quality code. LyX has been haunted by problems coming from +unfinished projects by people who have left the team. Those problems will hopefully disappear if the code is easy to hand over to somebody else. +In general, if you want to contribute to the main source, we expect at least +that you: + +- the most important rule first: kiss (keep it simple stupid), always + use a simple implementation in favor of a more complicated one. + This eases maintenance a lot. +- write good C++ code: Readable, well commented and taking advantage of the + OO model. Follow the formatting guidelines. See Formatting. +- adapt the code to the structures already existing in LyX, or in the case + that you have better ideas, discuss them on the developer's list before + writing the code. +- take advantage of the C++ standard library. especially don't use + custom containers when a standard container is usable; learn to use + the algorithms and functors in the standard library. +- be aware of exceptions and write exception safe code. See Exceptions. +- document all variables, methods, functions, classes etc. We are + using the source documentation program doxygen, a program that handles + javadoc syntax, to document sources. You can download doxygen from : + + http://www.stack.nl/~dimitri/doxygen/ + +- we have certain code constructs that we try to follow. See Code + Constructs. + + +Submitting Code +--------------- + +It is implicitly understood that all patches contributed to The LyX +Project is under the Gnu General Public License, version 2 or later. +If you have a problem with that, don't contribute code. + +Also please don't just pop up out of the blue with a huge patch (or +small) that changes something substantial in LyX. Always discuss your +ideas with the developers on the developer's mailing list. + +When you create the patch, please use "diff -up" since we find that a +lot easier to read than the other diff formats. Also please do not +send patches that implements or fixes several different things; several +patches is a much better option. + +We also require you to provide a ChangeLog entry with every patch, this +describes shortly what the patch is doing. The ChangeLog entry follows +this syntax: + +1999-12-13 Lars Gullik Bjønnes + + * src/support/lyxstring.C (find): assert bug fixed. + +Note that there are specific ChangeLogs for most directories; use those +rather than the top-level one. + +Code Constructs +--------------- + +We have several guidelines on code constructs, some of these exist to +make the code faster, others to make the code clearer. Yet others +exist to allow us to take advantage of the strong type checking +in C++. + +- Declaration of variables should wait as long as possible. The rule + is: "Don't declare it until you need it." In C++ there are a lot of + user defined types, and these can very often be expensive to + initialize. This rule connects to the next rule too. + +- declare the variable as const if you don't need to change it. This + applies to POD types like int as well as classes. + +- Make the scope of a variable as small as possible. + +- Make good use of namespaces. Prefer anonymous namespaces to declaring + "static" for file scope. + +- Prefer preincrement to postincrement whenever possible. + Preincrement has potential of being faster than postincrement. Just + think about the obvious implementations of pre/post-increment. This + rule applies to decrement too. + + ++T; + --U; + -NOT- + T++; // wrong + U--; // wrong + +- Try to minimize evaluation of the same code over and over. This is + aimed especially at loops. + + Container::iterator end = large.end(); + for (Container::iterator it = large.begin(); it != end; ++it) { + ...; + } + -NOT- + for (Container::iterator it = large.begin(); + it != large.end(); ++it) { + ...; + } + +- For functions and methods that return a non-POD type T, return T + const instead. This gives better type checking, and will give a + compiler warning when temporaries are used wrongly. + + T const add(...); + -NOT- + T add(...); + +- Avoid using the default cases in switch statements unless you have + too. Use the correct type for the switch expression and let the + compiler ensure that all cases are exhausted. + + enum Foo { + foo, + bar + }; + Foo f = ...; + switch (f) { + case foo: ...; break; + case bar: ...; break; + default: ...; break; // not needed and would shadow a wrong use of Foo + } + +Exceptions +---------- + +Even if LyX currently is not using exceptions we need to be aware of +them. One important thing to realize is that you often do not have to +use throw, try or catch to be exception safe. Let's look at the +different types of exceptions safety: (These are taken from Herb +Sutter's book[ExC++] + +" +1. Basic guarantee: Even in the presence of exceptions thrown by T or + other exceptions, Stack objects don't leak resources. + Note that this also implies that the container will be + destructible and usable even if an exception is thrown while + performing some container operation. However, if an exception + is thrown, the container will be in a consistent, but not + necessarily predictable, state. Containers that support the + basic guarantee can work safely in some settings. + +2. Strong guarantee: If an operation terminates because of an + exception, program state will remain unchanged. + This always implies commit-or-rollback semantics, including + that no references or iterators into the container be + invalidated if an operation fails. For example, if a Stack + client calls Top and then attempts a Push that fails because + of an exception, then the state of the Stack object must be + unchanged and the reference returned from the prior call to + Top must still be valid. For more information on these + guarantees, see Dave Abrahams's documentation of the SGI + exception-safe standard library adaption at: + + http://www.stlport.org/doc/exception_safety.html + + Probably the most interesting point here is that when you + implement the basic guarantee, the strong guarantee often + comes for free. For example, in our Stack implementation, + almost everything we did was needed to satisfy just the basic + guarantee -- and what's presented above very nearly satisfies + the strong guarantee, with little of no extra work. Not half + bad, considering all the trouble we went to. + + In addition to these two guarantees, there is one more + guarantee that certain functions must provide in order to make + overall exception safety possible: + +3. Nothrow guarantee: The function will not emit an exception under any + circumstances. + Overall exception safety isn't possible unless certain + functions are guaranteed not to throw. In particular, we've + seen that this is true for destructors; later in this + miniseries, we'll see that it's also needed in certain helper + functions, such as Swap(). +" + +For all cases where we might be able to write exception safe functions +without using try, throw or catch we should do so. In particular we +should look over all destructors to ensure that they are as exception +safe as possible. + +Later when more compiler support exceptions sufficiently well we will +begin using them too. One reason for this is that the C++ standard +library actually requires exceptions, e.g. "new" will throw +bad_allocation if the requested memory is not available. + + +Formatting +---------- + +* Only one declaration on each line. + int a; + int b; + -NOT- + int a, b; // wrong + This is especially important when initialization is done at the same + time: + string a("Lars"); + string b("Gullik"); + -NOT- + string a("Lars"), b("Gullik"); // wrong + +* Pointers and references + char * p = "flop"; + char & c = *p; + -NOT- + char *p = "flop"; // wrong + char &c = *p; // wrong + + Some time ago we had a huge discussion on this subject and after + convincing argumentation from Asger this is what we decided. Also note + that we will have: + char const * p; + -NOT- + const char * p; // wrong + +* Operator names and parentheses + operator==(type) + -NOT- + operator == (type) // wrong + + The == is part of the function name, separating it makes the + declaration look like an expression. + +* Function names and parentheses + void mangle() + -NOT- + void mangle () // wrong + +* Enumerators + enum { + one = 1, + two = 2, + three = 3 + }; + -NOT- + enum { one = 1, two = 2, three 3 }; // wrong + -NOT- + enum { + ONE = 1, + TWO = 2, + THREE = 3 + }; * Naming rules for classes - Use descriptive but simple and short names. For stuff specific to LyX use LyX as prefix. Some modules, like mathed or spellchecker, could have other prefixes. + [I am not so sure about the LyX prefix] - Class names are usually capitalized, and function names lowercased. - Enums are in CAPS. + Enums are named like Classes, values are usually in lower-case. - Long variables are named like thisLongVariableName. + New types are capitalized, so this goes for typedefs, classes, structs + and enums. * Formatting - - Please adapt the formatting of your code to the setting in LyX in that - particular file. Lars and Asger are slowly, but surely moving the source - towards Linux kernel style formatting, aka K&R style. We suggest that you - also do this, but this is NOT something that has been decided generally. - + - Adapt the formatting of your code to the one used in the + other parts of LyX. In case there is different formatting for + the same construct, use the one used more often. * Use existing structures - - Use LString whereever possible. LyX will someday move to Unicode, and - that will be easy if everybody uses LString now. + - Use string wherever possible. LyX will someday move to Unicode, and + that will be easy if everybody uses string now. - Check out the filename and path tools in filetools.h - - Use the Error class to report errors and messages + - Check out the string tools in lstring.h, and the SubString class + and the regex class. + + - Use the DebugStream class to report errors and messages using + the lyxerr instantiation. [add description of other existing structures] * Declarations - + - Use this order for the access sections of your class: public, protected, private. The public section is interesting for every user of the class. The private section is only of interest for the - implementors of the class (you). - - - Avoid to declare global objects in the declaration file of the class. - If the same variable is used for all object, use a static member. + implementors of the class (you). [Obviously not true since this is + for developers, and we do not want one developer only to be able to + read and understand the implementation of class internals. Lgb] - - Avoid global or static variables. An exception to this rule is + - Avoid declaring global objects in the declaration file of the class. + If the same variable is used for all objects, use a static member. + + - Avoid global or static variables. An exception to this rule is very private stuff like the math stack. - - Use the const keyword like this: char const * instead of const char * - because this is more logical. +* File headers + + - If you create a new file, the top of the file should look something + like this : + + /** + * \file NewFile.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Kaiser Sose + * + * Full author contact details are available in file CREDITS + */ * Documentation - The documentation is generated from the header files. - You document for the other developers, not for yourself. - - You should document what the funtion do, not the implementation. + - You should document what the function does, not the implementation. - in the .C files you document the implementation. - - Short description (///), large description (/** ... */) - (someone explain this please) - - You make the documentation by doing "make srcdoc" in the root, - and then you'll find HTML in the srcdoc/ directory. Read with - Netscape for best results. + - Single line description (///), multiple lines description (/** ... */) + - see the doxygen webpage referenced above * NAMING RULES FOR USER-COMMANDS - + Here's the set of rules to apply when a new command name is introduced: - - 1) Use the object.event order. That is, use `word-forward' instead of + + 1) Use the object.event order. That is, use `word-forward' instead of `forward-word'. 2) Don't introduce an alias for an already named object. Same for events. 3) Forward movement or focus is called `forward' (not `right'). @@ -96,11 +355,39 @@ hopefully disappear if the code is easy to hand over to somebody else. 8) The end of an object is called `end'. -* Using external GUI constructors (XForms fdesign) + ************************************************************* + + How to create class interfaces. + (a.k.a How Non-Member Functions Improve Encapsulation) + ====================================================== + + I recently read an article by Scott Meyers in C/C++ User's +Journal (Vol.18,No.2), where he makes a strong case on how non-member +functions makes classes more encapsulated, not less. Just skipping +to the core of this provides us with the following algorithm for +deciding what kind of function to add to a class interface: + + - We need to add a function f to the class C's API. + + if (f needs to be virtual) + make f a member function of C; + else if (f is operator>> or operator<<) { + make f a non-member function; + if (f needs access to non-public members of C) + make f a friend of C; + } else if (f needs type conversions on its left-most argument) { + make f a non-member function; + if (f needs access to non-public members of C) + make f a friend of C; + } else if (f can be implemented via C's public interface) + make f a non-member function; + else + make f a member function of C; + +(I'll fill in more from Scott Meyers article when time allows.) + +References +---------- - - Fdesign generated files should not be changed at all. The only changes - needed are gettext, compability with 0.81 or when you have made your own - xforms objects and have just a dummy in the .fd file in place of your - own. In case you have to change the generated files for any of the - reasons above, you should provide a patch against the clean generated - file. Your callbacks must be in a separate file. +[ExC++] Sutter, Herb. Exceptional C++: 47 engineering puzzles, + programming problems, and solutions. ISBN 0-201-61562-2