Latest revision |
Your text |
Line 3: |
Line 3: |
|
| |
|
| Being part of the GNU project, Octave inherits the [https://www.gnu.org/prep/standards/standards.html#Writing-C GNU coding standards]. | | Being part of the GNU project, Octave inherits the [https://www.gnu.org/prep/standards/standards.html#Writing-C GNU coding standards]. |
|
| |
| See also the GNU Octave [[Octave style guide]] for how to write m-files.
| |
|
| |
|
| == Formatting == | | == Formatting == |
|
| |
| === Line Length ===
| |
|
| |
| There is no fixed line length. In general, strive for clarity and readability and use your own judgement.
| |
|
| |
| Everyone has access to monitors with more than 80 columns, but even so, exceptionally long lines can be hard to read. However, keeping code together on a line that is logically one unit does improve readability.
| |
|
| |
|
| === Indentation === | | === Indentation === |
|
| |
|
| * Use only spaces, with 2 spaces per indent.
| | Use only spaces, and indent 2 spaces at a time. |
| * Tabs are prohibited.
| |
|
| |
|
| ==== Functions, class, struct, enum ====
| | We use spaces for indentation. Absolutely do not use tabs in your code. |
| | You should probably set your editor to emit spaces when you hit the tab key. |
|
| |
|
| The curly braces defining the beginning and end of the block should appear on their own line.
| | === Line Length === |
| | |
| The braces should not be indented, i.e., they align at the same indentation level as the keyword such as {{codeline|class}}.
| |
| | |
| The body of the block is indented.
| |
| | |
| Note that class access specifiers {{codeline|public}}, {{codeline|protected}}, {{codeline|private}} are not indented.
| |
| | |
| Example:
| |
| | |
| <syntaxhighlight lang="cpp">
| |
| class MatrixType
| |
| {
| |
| public:
| |
| enum matrix_type
| |
| {
| |
| Unknown = 0,
| |
| Full,
| |
| Rectangular
| |
| };
| |
| | |
| }
| |
| </syntaxhighlight>
| |
| | |
| ==== Control structures (if, while, ...) ==== | |
| | |
| When indenting, indent the statement after control structures (like {{codeline|if}}, {{codeline|while}}, etc.).
| |
| | |
| If there is a compound statement, indent ''both'' the curly braces and the body of the statement (so that the body gets indented by ''two'' indents).
| |
| | |
| Example:
| |
| | |
| <syntaxhighlight lang="cpp">
| |
| if (have_args)
| |
| {
| |
| idx.push_back (first_args);
| |
| have_args = false;
| |
| }
| |
| else
| |
| idx.push_back (make_value_list (args, arg_nm, tmp));
| |
| </syntaxhighlight>
| |
| | |
| If you have nested {{codeline|if}} statements, use extra braces for extra clarification.
| |
| | |
| ==== Switch statements ====
| |
| | |
| Indent ''both'' the curly braces and the body of the switch statement (so that the body gets indented by ''two'' indents).
| |
| | |
| However, the {{codeline|case}} statement is not doubly indented and instead aligns with the first brace.
| |
| | |
| <syntaxhighlight lang="cpp">
| |
| switch (info)
| |
| {
| |
| case -1:
| |
| {
| |
| cout << "function failed\n";
| |
| return false;
| |
| }
| |
| | |
| case 0:
| |
| return true;
| |
| }
| |
| </syntaxhighlight>
| |
| | |
| ==== #ifdef directives ====
| |
| | |
| Indent code that follows a conditional processor directive such as {{codeline|#ifdef}} or {{codeline|#else}}.
| |
| | |
| Example
| |
| | |
| <syntaxhighlight lang="cpp">
| |
| #if defined (HAVE_CONFIG_H)
| |
| # include "config.h"
| |
| #endif
| |
| </syntaxhighlight>
| |
| | |
| The '#' character may also be placed with the directive rather than remaining in column 1 if this looks better.
| |
| | |
| ==== Split long expressions ====
| |
| | |
| Split long expressions in such a way that a continuation line starts
| |
| with an operator rather than identifier. If the split occurs inside
| |
| braces, continuation should be aligned with the first char after the
| |
| innermost braces enclosing the split. Example:
| |
| | |
| <syntaxhighlight lang="cpp">
| |
| SVD::type type = ((nargout == 0 || nargout == 1)
| |
| ? SVD::sigma_only
| |
| : (nargin == 2) ? SVD::economy : SVD::std);
| |
| </syntaxhighlight>
| |
| | |
| ==== Optional braces ====
| |
| | |
| Consider putting extra braces around a multi-line expression to make it
| |
| more readable, even if they are not necessary. Also, do not hesitate to
| |
| put extra braces anywhere if it improves clarity.
| |
| | |
| === Pointer and Reference appearance ===
| |
| | |
| Declarations of pointers have the '*' character cuddled with the ''name'' of the variable.
| |
| | |
| <syntaxhighlight lang="cpp">
| |
| unsigned int *pointer_variable;
| |
| </syntaxhighlight>
| |
| | |
| However, references have the '&' character cuddled with the ''type'' of the variable.
| |
| | |
| <syntaxhighlight lang="cpp">
| |
| unsigned int& reference_variable;
| |
| </syntaxhighlight>
| |
| | |
| === Miscellaneous ===
| |
| | |
| The negation operator is written with a space between the operator
| |
| and its target, e.g., {{codeline|! A}}.
| |
| | |
| === Function headers ===
| |
| | |
| In general, in non-header files, format function headers like this:
| |
| | |
| <syntaxhighlight lang="cpp">
| |
| static bool
| |
| matches_patterns (const string_vector& patterns, int pat_idx,
| |
| int num_pat, const std::string& name)
| |
| </syntaxhighlight>
| |
| | |
| The return type of the function and any modifiers are specified on the first
| |
| line. The function name on the second line should start in column 1, and
| |
| multi-line argument lists should be aligned on the first character after the open
| |
| parenthesis. Put a space before the left open parenthesis and after
| |
| commas, for both function definitions and function calls.
| |
| | |
| For header files, or in class definitions, it may look better not to split the return type from the rest of the function header. Use your own judgement.
| |
| | |
| === Class declarations ===
| |
| | |
| The access specifier ({{codeline|public}}, {{codeline|protected}}, {{codeline|private}}) should always be stated rather than relying on the C++ language defaults for a particular object (for example, "{{codeline|class}}" = "{{codeline|private}}").
| |
| | |
| Within a class, the different access blocks should appear in the order 1) {{codeline|public}}, 2) {{codeline|protected}}, 3) {{codeline|private}}.
| |
| | |
| Within an access block, member functions (methods) should be specified before member variables. If there are both member functions and member variables use
| |
| | |
| //--------
| |
| | |
| between the sections to visually separate the two categories.
| |
| | |
| === Namespace ===
| |
| | |
| All code should be in the {{codeline|octave}} namespace or in a namespace below it.
| |
| | |
| Namespaces should start and stop using the special macros {{codeline|OCTAVE_BEGIN_NAMESPACE(XXX)}} and {{codeline|OCTAVE_END_NAMESPACE(XXX)}}. There is no indentation of code that is placed into namespaces using these macros.
| |
| | |
| Example
| |
| | |
| {{Code|Use of namespace macros|<syntaxhighlight lang="cpp">
| |
| OCTAVE_BEGIN_NAMESPACE(octave)
| |
| | |
| OCTAVE_BEGIN_NAMESPACE(math)
| |
| | |
| template <typename T>
| |
| void
| |
| umfpack_report_control (const double *Control);
| |
| | |
| OCTAVE_END_NAMESPACE(math)
| |
| OCTAVE_END_NAMESPACE(octave)
| |
| </syntaxhighlight>}}
| |
| | |
| If bare namespace directives must be used, as occasionally is required in Qt code, then the code within the namespace should be indented.
| |
| | |
| {{Code|bare namespace usage|<syntaxhighlight lang="cpp">
| |
| // Note indentation and that functions are not defined as "octave::math::foo:foo"
| |
| namespace octave
| |
| {
| |
| namespace math
| |
| {
| |
| foo::foo (...)
| |
| {
| |
| ...;
| |
| }
| |
| }
| |
| }
| |
| </syntaxhighlight>}}
| |
| | |
| ==== Other Guidelines ====
| |
| * Do not use {{codeline|using XXX;}} directives
| |
| * Do not declare anything on the {{codeline|std::}} namespace
| |
| | |
| == Naming ==
| |
| | |
| Use lowercase names if possible. Uppercase is acceptable for variable names consisting of 1-2 letters. Do not use mixed case (a.k.a. CamelCase) names.
| |
|
| |
|
| === Member Variables ===
| | Keep the length of source lines to 79 characters or less, for maximum |
| | | readability in the widest range of environments. This is inherited from |
| Member variables should use the prefix "m_" whenever possible.
| | the [https://www.gnu.org/prep/standards/standards.html#Formatting GNU Coding Standards]. |
| | |
| === Class Variables ===
| |
| | |
| Class variables should use the prefix "s_" (for "static") whenever possible.
| |
| | |
| === Filenames ===
| |
| | |
| As with m-files, the file name of a C++ source file containing a class should match the name of the class defined within the file. For example, "password.h" defines the class "password" rather than "passwd.h" which is a common abbreviation for "password".
| |
|
| |
|
| == Header Files == | | == Header Files == |
Line 228: |
Line 23: |
| === Order of Includes === | | === Order of Includes === |
|
| |
|
| In source files (not headers files), use the following order with an empty line between each section:
| | Use the following order with an empty line between each section: |
|
| |
|
| # config.h | | # config.h |
| # The C++ wrappers for C headers (cstdlib, cassert, etc.) | | # The C++ wrappers for C headers (cstdlib, cassert, etc.) |
| # C++ standard library headers (iostream, list, map, etc.) | | # C++ standard library headers (iostream, list, map, etc.) |
| | # Other POSIX headers (sys/types.h, unistd.h, etc., no need to use {{codeline|#if defined (HAVE_FOO_H)}} if existence is guaranteed because of gnulib) |
| # Other library header files (glpk.h, curl.h, etc., should be protected by {{codeline|#if defined (HAVE_FOO_H)}} since they may be missing on the build system) | | # Other library header files (glpk.h, curl.h, etc., should be protected by {{codeline|#if defined (HAVE_FOO_H)}} since they may be missing on the build system) |
| # Octave's liboctave headers | | # Octave's liboctave headers |
| # Octave's libinterp headers | | # Octave's libinterp headers |
| # Octave's libgui headers
| |
|
| |
| Other POSIX headers (sys/types.h, unistd.h, etc., should not be included directly into Octave sources. For portability, use a wrapper function. Anything you need is probably already available as a wrapper around a function or header provided by gnulib. See the files in liboctave/wrappers. This is necessary because although gnulib is great for portability, it does not generally work well with C++.
| |
|
| |
| Similarly, Windows headers should not be included directly into Octave sources. Wrappers that provide the needed functionality in an OS-independent way should be used instead. This is almost always possible and there are many examples in the Octave sources.
| |
|
| |
|
| Each grouping of header files should be alphabetized unless there is some | | Each grouping of header files should be alphabetized unless there is some |
Line 246: |
Line 37: |
| {{Path|oct-parse.in.yy}} and there is a comment in the file for that one. | | {{Path|oct-parse.in.yy}} and there is a comment in the file for that one. |
|
| |
|
| There is a strict ordering of header files/libraries that must be followed. There are '''no exceptions''' to these rules:
| | == Other C++ features == |
| | |
| * The functions in liboctave/wrappers may only use headers and symbols from gnulib, standard libraries, or OS-dependent libraries. They '''must not''' use any headers or symbols from other parts of liboctave, libinterp, or libgui.
| |
| * liboctave '''must not''' use any headers or symbols from libinterp or libgui. It must be fully functional without the interpreter or GUI.
| |
| * libinterp '''must not''' use any headers or symbols from libgui. It must be fully functional without the GUI.
| |
| | |
| As much as possible, header files should be independent of other header files.
| |
| | |
| Header files '''must not''' include config.h. Instead, they should begin by including octave-config.h.
| |
| | |
| Header files should not use any "#if defined (HAVE_FEATURE)" conditionals. This is not quite true yet, but we are almost there. '''No new conditionals may be added.'''
| |
| | |
| == C++ features == | |
| | |
| === references ===
| |
| | |
| Use references when passing variables that will be changed by a subroutine rather than the C-style method of passing pointers.
| |
| | |
| {| class="wikitable"
| |
| ! style="color:green;" | good
| |
| ! style="color:darkred;" | bad
| |
| |-
| |
| | <syntaxhighlight lang="c++">
| |
| void foo (int& a_ref)
| |
| {
| |
| // foo changes content of `a_ref`
| |
| a_ref = a_ref + 1;
| |
| }
| |
| | |
| void bar ()
| |
| {
| |
| int a = 42;
| |
| foo (a);
| |
| }
| |
| </syntaxhighlight>
| |
| | <syntaxhighlight lang="c++">
| |
| void foo (int *a_ptr)
| |
| {
| |
| // foo changes content of `a_ptr`
| |
| *a_ptr = *aptr + 1;
| |
| }
| |
| | |
| void bar ()
| |
| {
| |
| int a = 42;
| |
| foo (&a);
| |
| }
| |
| </syntaxhighlight>
| |
| |}
| |
| | |
| When passing variables that are large, but will not be changed in a subroutine (read-only), use {{codeline|const}} references. This helps avoid overflowing the finite stack capacity of a program while still ensuring that read-only access is enforced.
| |
| | |
| {| class="wikitable"
| |
| ! style="color:green;" | good
| |
| ! style="color:darkred;" | bad
| |
| |-
| |
| | <syntaxhighlight lang="c++">
| |
| void foo (const std::string& str_ref)
| |
| {
| |
| // foo does not change content of `str_ref`
| |
| }
| |
| | |
| void bar ()
| |
| {
| |
| std::string str ("This is a large variable, however as a reference it will take up just 8 bytes on the stack when passed to the subroutine foo()");
| |
| foo (str);
| |
| }
| |
| </syntaxhighlight>
| |
| | <syntaxhighlight lang="c++">
| |
| void foo (std::string str_copy)
| |
| {
| |
| // foo does not change content of `str_copy`
| |
| }
| |
| | |
| void bar ()
| |
| {
| |
| std::string str ("This is a large variable that will be copied on to the stack and passed as a temporary variable to the subroutine foo()");
| |
| foo (str);
| |
| }
| |
| </syntaxhighlight>
| |
| |}
| |
| | |
| === new/delete ===
| |
| | |
| Pointers that will be allocated memory with {{codeline|new}} should be initialized with the C++ literal {{codeline|nullptr}}, not the numerical value 0 or the macro {{codeline|NULL}}.
| |
| | |
| The {{codeline|delete}} keyword accepts {{codeline|nullptr}} and programmers should not put an {{codeline|if (ptr)}} guard around {{codeline|delete}}.
| |
| | |
| {| class="wikitable"
| |
| ! style="color:green;" | good
| |
| ! style="color:darkred;" | bad
| |
| |-
| |
| | <syntaxhighlight lang="c++">
| |
| delete ptr;
| |
| </syntaxhighlight>
| |
| | <syntaxhighlight lang="c++">
| |
| if (ptr)
| |
| delete ptr;
| |
| </syntaxhighlight>
| |
| |}
| |
| | |
| === lambda expressions ===
| |
| | |
| When capturing variables from the surrounding function, explicitly list the variables being captured rather than relying on a default capture by value (`[=]`) or by reference (`[&]`). This more clearly captures the programmer's intent and makes the code more understandable.
| |
| | |
| === std::string ===
| |
| | |
| When an empty string is required, use <code>""</code>, rather than creating an empty
| |
| string object with <code>std::string ()</code>.
| |
| | |
| === auto ===
| |
| | |
| Use of {{codeline|auto}} is allowed only where it helps readability
| |
| and local variables.
| |
| | |
| * Never use auto for class members.
| |
| * Do not use {{codeline|auto}} unless the type really is obscure.
| |
| * Beware of copy when using {{codeline|auto}} in for loops. Pass by reference and use {{codeline|const}} unless you're dealing with simple types such as {{codeline|int}}. See [http://lists.gnu.org/archive/html/octave-maintainers/2016-06/msg00144.html 'auto' uses and for-range loops] on the maintainers mailing list for more details.
| |
| | |
| === C++ style casting ===
| |
| | |
| Always use one of the four C++ long style casting forms ({{codeline|static_cast}}, {{codeline|dynamic_cast}}, {{codeline|reinterpret_cast}}, {{codeline|const_cast}}) rather than C-style forms (type cast {{codeline|(new_type) variable}} or the function form {{codeline|new_type (variable)}}).
| |
| | |
| === C++11 features ===
| |
| | |
| A C++11 compatible compiler is required for [[Building | building Octave]]. Please make use of all C++11 features.
| |
| | |
| === C++14, C++17, C++20 features ===
| |
| | |
| Try to avoid C++14, C++17, or C++20 features. Octave is widely used in very old systems and we want them to be able to use up to date versions of Octave. Building a recent compiler in such systems is not a trivial task so the limitation must happen
| |
| in Octave.
| |
| | |
| If the implementation using a C++14, C++17, or C++20 feature is very beneficial, make it optional via <code>configure</code> feature detection or also implement an alternative code in the absence of said feature. In any case, please get in contact with the Octave maintainers on [https://octave.discourse.group/c/maintainers/7 Discourse].
| |
| | |
| <syntaxhighlight lang="cpp">
| |
| #if defined (HAVE_THIS_C14_FEATURE)
| |
| // code that really needs it
| |
| #else
| |
| // alternative code in its absence
| |
| #endif
| |
| </syntaxhighlight>
| |
| | |
| == Doxygen ==
| |
| | |
| Doxygen documentation can be a great help when developing octave however the current state has a lot of room for improvement. For more information about Doxygen in Octave look at [[Doxygen]].
| |
| | |
| === Doxygen Style Guide ===
| |
| | |
| Doxygen allows for a variety of commenting styles. In order to maintain uniformity across the entire project the following rules should be applied:
| |
|
| |
|
| * For Doxygen comments use only {{codeline|//!}} and NOT {{codeline|/*! ... */}}, regardless of the size of the block comment
| | === C++11 === |
| * Use {{codeline|@}} for any [https://www.stack.nl/~dimitri/doxygen/manual/commands.html Doxygen Special Commands]
| |
| * Use as little formatting as possible. Restrict to [https://www.stack.nl/~dimitri/doxygen/manual/markdown.html Markdown] and avoid HTML-markup.
| |
| * Do NOT use the {{codeline|@brief}} command, the first sentence will automatically be used as the summary description.
| |
| * The first sentence should describe briefly what the function does and end with a period.
| |
| * Leave a blank line between the Doxygen comment and function definition.
| |
|
| |
|
| An example of properly used Doxygen would look like:
| | Do not use C++11 features. Octave is widely used in very old systems and we |
| | want them to be able to use up to date versions of Octave. Building a recent |
| | compiler in such systems is not a trivial task so the limitation must happen |
| | in Octave. See [https://lists.gnu.org/archive/html/octave-maintainers/2014-11/msg00069.html A case for C++11] in the maintainers mailing list. |
|
| |
|
| <syntaxhighlight lang="cpp">
| | As of Octave 4.2, Octave's configure will enable C++11 if the compiler |
| //! Does something interesting with its arguments.
| | supports it. Still, do not use C++11 features. |
| //!
| |
| //! Long comment with **bold** special commands.
| |
| //!
| |
| //! @param some_param Really should figure out what to do.
| |
| //! @param another_param Does something cool with @p some_param.
| |
| //!
| |
| //! And some example using syntax highlighting:
| |
| //!
| |
| //! @code{.cc}
| |
| //! double v = 1.0;
| |
| //! int n = 2;
| |
| //! some_function (v, n);
| |
| //! @endcode
| |
|
| |
|
| void
| | An exception: code that requires C++11 feature must also implement an |
| some_function (double some_param, int another_param)
| | alternative code in the absence of said feature. In such case, use a |
| {
| | configure check. This increases maintenance a lot, must be used sparsely, |
| // ...
| | and requires approval from other maintainers. |
| }
| |
| </syntaxhighlight>
| |
|
| |
|
| == Comments ==
| | #if HAVE_THIS_C11_FEATURE |
| | // code that really needs it |
| | #else |
| | // alternative code in its absence |
| | #endif |
|
| |
|
| === FIXME notes ===
| | This decision may be revisited in the future once cross-compiling becomes |
| | more mature. |
|
| |
|
| The preferred comment mark for places that may need further attention is
| | === C++14 === |
| with {{codeline|FIXME:}} comments.
| |
|
| |
|
| [[Category:Development]]
| | Do not use C++14 features. Same reason as why C++11 features are not allowed. |