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 <larsbj@lyx.org>
+
+ * 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').
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