]> git.lyx.org Git - lyx.git/blobdiff - development/Code_rules/Rules
update aastex documentation; remove Mike Ressler's address
[lyx.git] / development / Code_rules / Rules
index f065a90078b139d1df02750453233fe7ec26ca11..2212a6140b025464f648328a8aa073d6c61eee05 100644 (file)
 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').
@@ -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