1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
|
<HTML>
<HEAD>
<TITLE>Coding conventions</TITLE>
<LINK HREF="doxygen.css" REL="stylesheet" TYPE="text/css">
<LINK HREF="style_ini.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<A href="index.html">Home</A> ·
<A href="classes.html">Classes</A> ·
<A href="annotated.html">Annotated Classes</A> ·
<A href="modules.html">Modules</A> ·
<A href="functions_func.html">Members</A> ·
<A href="namespaces.html">Namespaces</A> ·
<A href="pages.html">Related Pages</A>
<HR style="height:1px; border:none; border-top:1px solid #c0c0c0;">
<!-- Generated by Doxygen 1.8.5 -->
</div><!-- top -->
<div class="header">
<div class="headertitle">
<div class="title">Coding conventions </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><h1 style="margin-top:40px; border-top:4px solid grey; text-align:left;">Formatting</h1>
<p>All OpenMS files use a tab width of two. Use the command <code>set tabstop=2</code> in <code>vi</code> or <code>set-variable tab-width 2</code> if you are using <code>emacs</code>. For those two editors, the indentation behavior should be set automatically throught the standard file headers (see below). Due to these ugly issues with setting the tabwidth in the editor, it is perfectly ok not to use tabs at all. In emacs, you can replace all tabs with the right number of spaces by typing the following keys: <code>C-x h</code> (to mark the whole buffer), then <code>M-x untabify RET</code>.</p>
<p>All lines in ASCII files (.C, .h, .cmake, ...) should have the svn property <em>svn:eol-style</em> set to <em>native</em>, allowing native line endings on each platform. This is desirable as Visual Studio for example will always insert CRLF even if the file is LF only, leading to a mixed line ending style for this file. Native eol style avoids this problem.</p>
<p>Matching pairs of opening and closing curly braces should be set to the same column:</p>
<div class="fragment"><div class="line"><span class="keywordflow">while</span> (<span class="keywordflow">continue</span> == <span class="keyword">true</span>)</div>
<div class="line">{</div>
<div class="line"> <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i < 10; i++)</div>
<div class="line"> {</div>
<div class="line"> ...</div>
<div class="line"> }</div>
<div class="line"></div>
<div class="line"> <span class="keywordflow">if</span> (x < 7)</div>
<div class="line"> {</div>
<div class="line"> ....</div>
<div class="line"> }</div>
<div class="line">}</div>
</div><!-- fragment --><p> The main reason for this rule is to avoid constructions like:</p>
<div class="fragment"><div class="line"><span class="keywordflow">if</span> (isValid(a))</div>
<div class="line"> <span class="keywordflow">return</span> 0;</div>
</div><!-- fragment --><p>which might later be changed to something like</p>
<div class="fragment"><div class="line"><span class="keywordflow">if</span> (isValid(a))</div>
<div class="line"> error = 0;</div>
<div class="line"> <span class="keywordflow">return</span> 0;</div>
</div><!-- fragment --><p>The resulting errors are hard to find. There are two ways to avoid these problems: (a) always use braces around a block (b) write everyting in a single line. We recommend method (a). However, this is mainly a question of personal style, so no explicit checking is performed to enforce this rule. However, if there is an else following the if statement the braces are mandatory! One exception is several if/else statements can be written as</p>
<div class="fragment"><div class="line"><span class="keywordflow">if</span> (cond1)</div>
<div class="line">{</div>
<div class="line"> ...</div>
<div class="line">}</div>
<div class="line"><span class="keywordflow">else</span> <span class="keywordflow">if</span> (cond2)</div>
<div class="line">{</div>
<div class="line"> ...</div>
<div class="line">}</div>
<div class="line"><span class="keywordflow">else</span> <span class="keywordflow">if</span> (cond3)</div>
<div class="line">{</div>
<div class="line"> ...</div>
<div class="line">}</div>
<div class="line"><span class="keywordflow">else</span></div>
<div class="line">{</div>
<div class="line"> ...</div>
<div class="line">}</div>
</div><!-- fragment --><p>which is save, because the first statement in each else branch is used, which is itself braced by the if branch.</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Sample .h file</h2>
<div class="fragment"><div class="line"><span class="comment">// -*- mode: C++; tab-width: 2; -*-</span></div>
<div class="line"><span class="comment">// vi: set ts=2:</span></div>
<div class="line"><span class="comment">//</span></div>
<div class="line">... copyright header, not shown ...</div>
<div class="line"><span class="comment">//</span></div>
<div class="line"><span class="comment">// --------------------------------------------------------------------------</span></div>
<div class="line"><span class="comment">// $Maintainer: Heinz Erhardt $</span></div>
<div class="line"><span class="comment">// $Authors: Heinz Erhardt $</span></div>
<div class="line"><span class="comment">// --------------------------------------------------------------------------</span></div>
<div class="line"></div>
<div class="line">#ifndef OPENMS_KERNEL_DPEAK_H</div>
<div class="line"><span class="preprocessor">#define OPENMS_KERNEL_DPEAK_H</span></div>
<div class="line"><span class="preprocessor"></span></div>
<div class="line"><span class="preprocessor">#include <<a class="code" href="Types_8h.html">OpenMS/CONCEPT/Types.h</a>></span></div>
<div class="line"></div>
<div class="line"><span class="preprocessor">#include <functional></span></div>
<div class="line"><span class="preprocessor">#include <sstream></span></div>
<div class="line"></div>
<div class="line"><span class="keyword">namespace </span>OpenMS</div>
<div class="line">{</div>
<div class="line"> ... the actual code goes here ...</div>
<div class="line">} <span class="comment">// namespace OpenMS</span></div>
<div class="line"></div>
<div class="line"><span class="preprocessor">#endif // OPENMS_KERNEL_DPEAK_H</span></div>
</div><!-- fragment --> <h2 style="margin-top:20px; border-top:1px solid grey;">Sample .C file</h2>
<div class="fragment"><div class="line"><span class="comment">// -*- mode: C++; tab-width: 2; -*-</span></div>
<div class="line"><span class="comment">// vi: set ts=2:</span></div>
<div class="line"><span class="comment">//</span></div>
<div class="line">... copyright header, not shown ...</div>
<div class="line"><span class="comment">//</span></div>
<div class="line"><span class="comment">// --------------------------------------------------------------------------</span></div>
<div class="line"><span class="comment">// $Maintainer: Heinz Erhardt $</span></div>
<div class="line"><span class="comment">// $Authors: Heinz Erhardt $</span></div>
<div class="line"><span class="comment">// --------------------------------------------------------------------------</span></div>
<div class="line"></div>
<div class="line">#include <OpenMS/KERNEL/DPeak.h></div>
<div class="line"></div>
<div class="line"><span class="keyword">namespace </span>OpenMS</div>
<div class="line">{</div>
<div class="line"> ... the actual code goes here ...</div>
<div class="line">} <span class="comment">// namespace OpenMS</span></div>
</div><!-- fragment --><p> Every <code>.h</code> file must be accompanied by a <code>.C</code> file, even if is just a ``dummy''. This way a global <code>make</code> will stumble across errors. <br/>
For template classes default instances with common template arguments should be put into the <code>.C</code> file. The varaible names of these instances start with <code>default_</code>. Here an example for the <code>DPeak</code> class: </p>
<div class="fragment"><div class="line"><span class="preprocessor">#include <<a class="code" href="DPeak_8h.html">OpenMS/KERNEL/DPeak.h</a>></span></div>
<div class="line"></div>
<div class="line"><span class="keyword">namespace </span>OpenMS</div>
<div class="line">{</div>
<div class="line"> DPeak<1> default_dpeak_1;</div>
<div class="line"> DPeak<2> default_dpeak_2;</div>
<div class="line">}</div>
</div><!-- fragment --><p> The compiler does instanciate the template and detects errors at compile time that way. Doing this saves your time! Otherwise the error is detected much later, when the test is compiles.</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">A note on templates: when (and why) should I write an _impl.h file?</h2>
<p>Simply speaking, _impl.h files are for templates what .C files are for ordinary classes. Remember that the definition of a class or function template has to be known at its point of instantiation. Therefore the implementation of a template is normally contained in the .h file. (No problem so far, things are even easier than for ordinary classes, because declaration and definition are given in the same file. You may like this or not.) Things get more complicated when certain design patterns (e.g., the factory pattern) are used which lead to "circular dependencies". Of course this is only a dependency of names, but it has to be resolved by separating declarations from definitions, at least for some of the member functions. In this case, a .h file can be written that contains most of the definitions as well as the declarations of the peculiar functions. Their definition is deferred to the _impl.h file ("impl" for "implementation"). The _impl.h file is included only if the peculiar member functions have to be instantiated. Otherwise the .h file should be sufficent. No .h file should include an _impl.h file.</p>
<h1 style="margin-top:40px; border-top:4px solid grey; text-align:left;">Class requirements</h1>
<p>Each OpenMS class should provide the following interface:</p>
<div class="fragment"><div class="line"><span class="keyword">class </span>OPENMS_DLLAPI Test</div>
<div class="line">{</div>
<div class="line"> <span class="keyword">public</span>:</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// default constructor</span></div>
<div class="line"> Test();</div>
<div class="line"></div>
<div class="line"> <span class="comment">// copy constructor</span></div>
<div class="line"> Test(<span class="keyword">const</span> Test& <a class="code" href="namespaceOpenMS_1_1Internal_1_1ClassTest.html#a69f942d7289d5ed2ffe3a00b12235d04">test</a>);</div>
<div class="line"></div>
<div class="line"> <span class="comment">// destructor</span></div>
<div class="line"> <span class="keyword">virtual</span> ~Test();</div>
<div class="line"></div>
<div class="line"> <span class="comment">// assignment operator</span></div>
<div class="line"> Test& operator = (<span class="keyword">const</span> Test& <a class="code" href="namespaceOpenMS_1_1Internal_1_1ClassTest.html#a69f942d7289d5ed2ffe3a00b12235d04">test</a>)</div>
<div class="line"> {</div>
<div class="line"> <span class="comment">//ALWAYS CHECK FOR SELF ASSIGNEMT!</span></div>
<div class="line"> <span class="keywordflow">if</span> (<span class="keyword">this</span> == &test) <span class="keywordflow">return</span> *<span class="keyword">this</span>;</div>
<div class="line"> <span class="comment">//...</span></div>
<div class="line"> <span class="keywordflow">return</span> *<span class="keyword">this</span>;</div>
<div class="line"> }</div>
<div class="line">};</div>
</div><!-- fragment --><p>There are however circumstances that allow to omit these methods:</p>
<ul>
<li>default constructor <br/>
Can be omitted when the class is entirely dependent on some information or another class. In this case you should declare the default constructor private!</li>
<li>destructor <br/>
Should be a virtual function, unless you have a very good reason why it shouldn't. (E.g., saving a vtable pointer.) Essentially, the reason is that otherwise an <code>operator delete</code> invocation on a pointer to a base class will fail badly.</li>
<li>copy constructor <br/>
Can be omitted when it will not be used anyway, e.g. for classes that represent an anlgorithm. In this case you should declare the copy constructor private!</li>
<li>assignment operator <br/>
Can be omitted when it will not be used anyway, e.g. for classes that represent an anlgorithm. In this case you should declare the assignment operator private!</li>
</ul>
<p>The OPENMS_DLLAPI macro on the first line is required for correctly building the DLL. The correct usage of this macro is explained in the <a class="el" href="namespaceOpenMS.html" title="Main OpenMS namespace. ">OpenMS</a> C++ guide!</p>
<h1 style="margin-top:40px; border-top:4px solid grey; text-align:left;">General rules</h1>
<h2 style="margin-top:20px; border-top:1px solid grey;">Primitive types</h2>
<p>OpenMS uses its own type names for primitive types. Use only the types defined in <code>OpenMS/include/OpenMS/CONCEPT/Types.h</code>!</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Namespaces</h2>
<p>The main OpenMS classes are implemented in the namespace <code>OpenMS</code>. Auxilary classes are implemented in <code>OpenMS::Internal</code>. There are some other namespaces e.g. for constants and exceptions.</p>
<p>Importing a whole namespace in a header files is forbidden. E.g.: </p>
<div class="fragment"><div class="line"><span class="keyword">using namespace </span>std; <span class="comment">//< Don't do this at home! </span></div>
</div><!-- fragment --><p> This could lead to name clashes when OpenMS is used together with other libraries. In source files (.C) it is however allowed.</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Accessors to members</h2>
<p>Accessors to protected or private members of a class are implemented as a pair of get-method and set-method. This is necessary as accessors that return mutable references to a member cannot be wrapped with Python!</p>
<div class="fragment"><div class="line"><span class="keyword">class </span>Test</div>
<div class="line">{</div>
<div class="line"> <span class="keyword">public</span>:</div>
<div class="line"> <span class="comment">// always implement a non-mutable get-method</span></div>
<div class="line"> <a class="code" href="group__Concept.html#gaba0996d26f7be2572973245b51852757">UInt</a> getMember()<span class="keyword"> const</span></div>
<div class="line"><span class="keyword"> </span>{</div>
<div class="line"> <span class="keywordflow">return</span> member_;</div>
<div class="line"> }</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// always implement a set-method</span></div>
<div class="line"> <span class="keywordtype">void</span> setMember(<a class="code" href="group__Concept.html#gaba0996d26f7be2572973245b51852757">UInt</a> name)</div>
<div class="line"> {</div>
<div class="line"> name_ = member_;</div>
<div class="line"> }</div>
<div class="line"> </div>
<div class="line"> <span class="keyword">protected</span>:</div>
<div class="line"> <a class="code" href="group__Concept.html#gaba0996d26f7be2572973245b51852757">UInt</a> member_;</div>
<div class="line">};</div>
</div><!-- fragment --><p>For members that are too large to be read with the get-method, modified and written back with the set-method, an additional non-const get-method can be implemented! </p>
<p>For primitive types a non-const get-method is strictly forbidden! For more complex types it should be present only when really necessary!</p>
<div class="fragment"><div class="line"><span class="keyword">class </span>Test</div>
<div class="line">{</div>
<div class="line"> <span class="keyword">public</span>:</div>
<div class="line"> <span class="keyword">const</span> vector<String>& getMember()<span class="keyword"> const</span></div>
<div class="line"><span class="keyword"> </span>{</div>
<div class="line"> <span class="keywordflow">return</span> member_;</div>
<div class="line"> }</div>
<div class="line"> </div>
<div class="line"> <span class="keywordtype">void</span> setMember(<span class="keyword">const</span> vector<String>& name)</div>
<div class="line"> {</div>
<div class="line"> name_ = member_;</div>
<div class="line"> }</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// if absolutely necessary implement a mutable get-method</span></div>
<div class="line"> vector<String>& getMember()</div>
<div class="line"> {</div>
<div class="line"> <span class="keywordflow">return</span> member_;</div>
<div class="line"> }</div>
<div class="line"></div>
<div class="line"> <span class="keyword">protected</span>:</div>
<div class="line"> vector<String> member_;</div>
<div class="line">};</div>
</div><!-- fragment --><h2 style="margin-top:20px; border-top:1px solid grey;">Use of the STL</h2>
<p>Many OpenMS classes base on STL classes. However, only the C++ Standard Library part of the STL must be used. This means that SGI extensions like <code>hash_set</code>, <code>hash_multiset</code>, <code>hash_map</code> and <code>hash_multimap</code> are not allowed!</p>
<h1 style="margin-top:40px; border-top:4px solid grey; text-align:left;">Exception handling</h1>
<p>No OpenMS program should dump a core if an error occurs. Instead, it should attempt to die as gracefully as possible. Furthermore, as OpenMS is a framework rather than an application, it should give the programmer ways to catch and correct errors. The recommended procedure to handle - even fatal - errors is to throw an exception. Uncaught exception will result in a call to <code>abort</code> thereby terminating the program.</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Exception classes</h2>
<p>All exceptions used in OpenMS are derived from <code>Exception::Base</code> defined in <code><a class="el" href="Exception_8h.html">CONCEPT/Exception.h</a></code>. A default constructor should not be implemented for these exceptions. Instead, the constructor of all derived exceptions should have the following signature:</p>
<div class="fragment"><div class="line">AnyException(<span class="keyword">const</span> <span class="keywordtype">char</span>* file, <span class="keywordtype">int</span> line, <span class="keyword">const</span> <span class="keywordtype">char</span>* <span class="keyword">function</span>[, ...]);</div>
</div><!-- fragment --><p> Additional arguments are possible but should provide default values (see <code>IndexOverflow</code> for an example).</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Throwing exceptions</h2>
<p>The <code>throw</code> directive for each exception should be of the form </p>
<div class="fragment"><div class="line"><span class="keywordflow">throw</span> AnyException(__FILE__, __LINE__, __PRETTY_FUNCTION__);</div>
</div><!-- fragment --><p>to simplify debugging. <code>__FILE__</code> and <code>__LINE__</code> are standard-defined preprocessor macros. The symbol <code>__PRETTY_FUNCTION__</code> works similar to a <code>char*</code> and contains the type signature of the function as well as its bare name, if the GNU compiler is being used. It is defined to <code><unknown></code> on other platforms. Exception::Base provides methods (<code>getFile</code>, <code>getLine</code>, <code>getFunction</code>) that allow the localization of the exception's cause.</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Catching exceptions</h2>
<p>As usual with C++, the standard way to catch an exeption should be by reference (and <em>not</em> by value). </p>
<div class="fragment"><div class="line"><span class="keywordflow">try</span></div>
<div class="line">{</div>
<div class="line"> <span class="comment">// some code which might throw</span></div>
<div class="line">}</div>
<div class="line"><span class="keywordflow">catch</span> ( Exception& e)</div>
<div class="line">{</div>
<div class="line"> <span class="comment">// Handle the exception, then possibly re-throw it:</span></div>
<div class="line"> <span class="comment">// throw; // the modified e</span></div>
<div class="line">}</div>
</div><!-- fragment --><h2 style="margin-top:20px; border-top:1px solid grey;">Specifying exceptions</h2>
<p>Exceptions are <b>not specified in the code</b> using the throw statement, as this forces the compiler to check that only the specified exceptions are thrown. This check not only increases the runtime, but may prevent efficient optimization of the code by the compiler. </p>
<p>However, thrown <b>exceptions must be documented</b> to tell the user which exceptions can be catched. </p>
<pre class="fragment">/**
@brief Silly function
@exception Exception::Foo is always thrown
*/
void myFunction()
{
throw Foo(__FILE__, __LINE__, __PRETTY_FUNCTION__);
}
</pre><h1 style="margin-top:40px; border-top:4px solid grey; text-align:left;">Naming conventions</h1>
<p>Reserved words of the C++ language and symbols defined e. g. in the STL or in the standard C library must not be used as names for classes or class members. Even if the compiler accepts it, such words typically mess up the syntax highlighting and are confusing for other developers, to say the least. Bad examples include: set, map, exp, log. (All developers: Add your favorites to this list whenever you stumble upon them!)</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">File names</h2>
<p>Header files and source files should be named as the classes they contain. Source files end in ".C", while header files end in ".h". File names should be capitalized exactly as the class they contain (see below). Each header/source file should contain one class only, although exceptions are possible for light-weight classes. </p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Underscores</h2>
<p>Usage of underscores in names has two different meanings: A trailing ``_'' at the end indicates that something is protected or private to a class. Apart from that, different parts of a name are sometimes separated by an underscore, and sometimes separated by capital letters. (The details are explained below.)</p>
<p>Note that according to the C++ standard, names that start with an underscore are reserved for internal purposes of the language and its standard library (roughly speaking), so you should never use them. </p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Class / type / namespace names</h2>
<p>Class names and type names always start with a capital letter. Different parts of the name are separated by capital letters at the beginning of the word. No underscores are allowed in type names and class names, except for the names of protected types and classes in classes, which are suffixed by an underscore. The same conventions apply for <code>namespace</code>s.</p>
<div class="fragment"><div class="line"><span class="keyword">class </span>Simple; <span class="comment">//ordinary class</span></div>
<div class="line"><span class="keyword">class </span>SimpleThing; <span class="comment">//ordinary class</span></div>
<div class="line"><span class="keyword">class </span>PDBFile; <span class="comment">//using an abbreviation</span></div>
<div class="line"><span class="keyword">class </span>Buffer_; <span class="comment">//protected or private nested class</span></div>
<div class="line"><span class="keyword">class </span>ForwardIteratorTraits_; <span class="comment">//protected or private nested class</span></div>
</div><!-- fragment --><h2 style="margin-top:20px; border-top:1px solid grey;">Variable names</h2>
<p>Variable names are all lower case letters. Distinguished parts of the name are separated using underscores ``<code>_</code>''. If parts of the name are derived from common acronyms (e.g. MS) they should be in upper case. Private or protected member variables of classes are suffixed by an underscore.</p>
<div class="fragment"><div class="line"><span class="keywordtype">int</span> simple; <span class="comment">//ordinary variable</span></div>
<div class="line"><span class="keywordtype">bool</span> is_found; <span class="comment">//ordinary variable</span></div>
<div class="line"><span class="keywordtype">string</span> MS_instrument; <span class="comment">//using an abbreviation</span></div>
<div class="line"><span class="keywordtype">int</span> counter_; <span class="comment">//protected or private member</span></div>
<div class="line"><span class="keywordtype">int</span> persistent_id_; <span class="comment">//protected or private member</span></div>
</div><!-- fragment --><p>No prefixing or suffixing is allowed to identify the variable type - this leads to completely illegible documentation and overly long variable names. </p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Function names/method names </h2>
<p>Function names (including class method names) always start with a lower case letter. Parts of the name are separated using capital letters (as are types and class names). They should be comprehensible, but as short as possible. The same variable names must be used in the declaration and in the definition. Arguments that are actually not used in the implementation of a function have to be commented out - this avoids compiler warnings. The argument of <code>void</code> functions (empty argument list) must omitted in both the declaration and the definition. If function arguments are pointers or references, the pointer or reference qualifier is appended to the variable type. It should not prefix the variable name.</p>
<div class="fragment"><div class="line"><span class="keywordtype">void</span> hello(); <span class="comment">//ordinary function, no arguments</span></div>
<div class="line"><span class="keywordtype">int</span> countPeaks(PeakArray <span class="keyword">const</span>& p); <span class="comment">//ordinary function</span></div>
<div class="line"><span class="keywordtype">bool</span> ignore(<span class="keywordtype">string</span>& <span class="comment">/* name */</span>); <span class="comment">//ordinary function with an unused argument</span></div>
<div class="line"><span class="keywordtype">bool</span> isAdjacentTo(Peak <span class="keyword">const</span> * <span class="keyword">const</span> * <span class="keyword">const</span> & p) <span class="keyword">const</span>; <span class="comment">//an ordinary function</span></div>
<div class="line"><span class="keywordtype">bool</span> doSomething_(<span class="keywordtype">int</span> i, <span class="keywordtype">string</span>& name); <span class="comment">//protected or private member function</span></div>
</div><!-- fragment --> <h2 style="margin-top:20px; border-top:1px solid grey;">Enums and preprocessor constants</h2>
<p>Enumerated values and preprocessor constants are all upper case letters. Parts of the name are separated by underscores.</p>
<div class="fragment"><div class="line"><span class="preprocessor">#define MYCLASS_SUPPORTS_MIN_MAX 0 //preprocessor constant</span></div>
<div class="line"><span class="preprocessor"></span><span class="keyword">enum</span> DimensionId { DIM_MZ = 0, DIM_RT = 1 }; <span class="comment">//enumerated values</span></div>
<div class="line"><span class="keyword">enum</span> DimensionId_ { MZ = 0, RT = 1 }; <span class="comment">//enumerated values</span></div>
</div><!-- fragment --><p>(You should avoid using the preprocessor anyway. Normally, <code>const</code> and <code>enum</code> will suffice unless something very special.) </p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Parameters</h2>
<p>Parameters in .ini files and elsewhere follow these conventions: </p>
<ul>
<li>
They consist of lower-case letters and underscores only. </li>
<li>
For numerical parametes the range of reasonable values is given. </li>
<li>
Where applicable units are given in the description. </li>
</ul>
<p>This rule applies to all kinds of parameter strings, both keys and string-values.</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Data files</h2>
<p>The correct capitalization of all data file extensions supported by <a class="el" href="namespaceOpenMS.html" title="Main OpenMS namespace. ">OpenMS</a> in documented in FileHandler::NamesOfTypes[]. The convention is to use only lowercase letters for file extensions. There are three exceptions: "ML" and "XML" are written in uppercase letters and "mzData" keeps its capital "D". Please remember to keep this consistent when adding new data files or writing new TOPP tools or UTILS (use correct capitalization for file type restrictions, here).</p>
<h1 style="margin-top:40px; border-top:4px solid grey; text-align:left;">Documentation</h1>
<h2 style="margin-top:20px; border-top:1px solid grey;">UML diagrams</h2>
<p>To generate UML diagrams use yEd and export the diagrams in png format. Do not forget to save also the corresponding .yed file. </p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Doxygen </h2>
<p>Each OpenMS class has to be documented using Doxygen. The documentation is inserted in Doxygen format in the header file where the class is defined. Documentation includes the description of the class, of each method, type declaration, enum declaration, each constant, and each member variable.</p>
<p>Longer pieces of documentation start with a brief description, followed by an empty line and a detailed description. The empty line is needed to separate the brief from the detailed description.</p>
<p>Descriptions of classes always have a brief section!</p>
<p>Please use the doxygen style of the following example for OpenMS: </p>
<pre class="fragment">/**
@defgroup DummyClasses Dummy classes
@brief This class contains dummy classes
Add classes by using the '@ingroup' command.
*/
/**
@brief Demonstration class.
A demonstration class for teaching doxygen
@note All classes need brief description!
@ingroup DummyClasses
*/
class Test
{
public:
/**
@brief An enum type.
The documentation block cannot be put after the enum!
*/
enum EnumType
{
int EVal1, ///< Enum value 1.
int EVal2 ///< Enum value 2.
};
/**
@brief constructor.
A more elaborate description of the constructor.
*/
Test();
/**
@brief Dummy function.
A normal member taking two arguments and returning an integer value.
The parameter @p dummy_a is an integer.
@param dummy_a an integer argument.
@param dummy_s a constant character pointer.
@see Test()
@return The dummy results.
*/
int dummy(int dummy_a, const char *dummy_s);
/// Brief description in one line.
int isDummy();
/**
@name Group of members.
Description of the group.
*/
//@{
/// Dummy 2.
void dummy2();
/// Dummy 3.
void dummy3();
//@}
protected:
int value; ///< An integer value.
};
</pre><p>The defgroup command indicates that a comment block contains documentation for a group of classes, files or namespaces. This can be used to categorize classes, files or namespaces, and document those categories. You can also use groups as members of other groups, thus building a hierarchy of groups. Using the ingroup command a comment block of a class, file or namespace will be added to the group or groups.</p>
<p>The groups (or modules as doxygen calls them) definded by the ingroup command should contain only the classes of special interest to the OpenMS user. Helper classes and such must be omitted.</p>
<p>Documentation which does not belong to a specific .C or .h file can be written into a separate Doxygen file (with the ending .doxygen). This file will also be parsed by Doxygen.</p>
<p>Open tasks are noted in the documentation of a header or a group using the todo command. The ToDo list is then shown in the doxygen menu under 'Related pages'. Each ToDo should be followed by a name in parentheses to indicated who is going to handle it.</p>
<p>These commands should be used as well:</p>
<ul>
<li><b>@todo</b> Necessary todo for the the next release. Should be done as soon as possible. <br/>
Please add the name of the responsible person in parentheses!</li>
<li><b>@improvement</b> Possible improvement, but not really necessary. <br/>
Please add the name of the responsible person in parentheses!</li>
<li><b>@deprecated</b> Deprecated class, that must be removed in the next release.</li>
<li><b>@experimental</b> Experimental class, that will perhaps not make it to the library.</li>
<li><b>@bug</b> Decrription of a bug in the class/method. <br/>
Please add the name of the finder in parentheses!</li>
</ul>
<p>Doxygen is not hard to learn, have a look at the manual :-)</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Commenting code</h2>
<p>The code for each .C file has to be commented. Each piece of code in OpenMS has to contain at least 5% of comments. The use of</p>
<pre class="fragment">// Comment text</pre><p> instead of C style comments</p>
<pre class="fragment">/* Comment text */ </pre><p> is recommended to avoid problems arising from nested comments. Comments should be written in plain english and describe the functionality of the next few lines.</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Examples</h2>
<p>Instructive programming examples can be provided in the <code>doc/code_examples</code> directory.</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Revision control</h2>
<p>OpenMS uses Subversion to manage different versions of the source files. For easier identification of the responsible person each OpenMS file contains the <code>$Maintainer:$</code> string in the preamble.</p>
<p>Examples of <code>.h</code> and <code>.C</code> files have been given above. In non-C++ files (Makefiles, (La)TeX-Files, etc.) the C++ comments are replaced by the respective comment characters (e.g. ``#'' for Makefiles, ``'' for (La)TeX). TeX will switch to math mode after a <code>$</code>, but you can work around this by writing something like</p>
<p><code>Latest SVN $ $Date:$ $</code> if you want to use it in texts; the one here expands to ``Latest SVN Date: 2007-01-19 13:47:36 +0100 (Fri, 19 Jan 2007) ''. Subversion does not turn on keyword substitution by default. See <code>svn -h propset</code> and <code>svn -h proplist</code> for details.</p>
<h1 style="margin-top:40px; border-top:4px solid grey; text-align:left;">Testing</h1>
<h2 style="margin-top:20px; border-top:1px solid grey;">General</h2>
<p>Each OpenMS class has to provide a test program. This test program has to check each method of the class. The test programs reside in the directory <code>source/TEST</code> are usually named <code><classname>_test.C</code>. The test program has to be coded using the class test macros as described in the OpenMS online reference. Special care should be taken to cover all special cases (e.g. what happens, if a method is called with empty strings, negative values, zero, null pointers etc.). Please activate the keyword substitution of '$Id$' for all tests with the following command: <code>svn propset svn:keywords Id <file></code>.</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Suplementary files</h2>
<p>If a test needs suplementary files, put these files in the <code>source/TEST/data/</code> folder. The name of suplementary files has to begin with the name of the tested class.</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Structure of a test program</h2>
<h3>Macros to start, finish and evaluate tests</h3>
<ul>
<li>
<code><a class="el" href="group__ClassTest.html#ga7a40a89e644997d4c2ff42b1068658e2" title="Begin of the test program for a given class. ">START_TEST(class_name, version)</a></code><br/>
Start of a class test file (initialization) </li>
<li>
<code><a class="el" href="group__ClassTest.html#gaefcd1ca1799d2395f7bbe3c50bcc8ff8" title="End of the test program for a class. ">END_TEST()</a></code><br/>
End of a class test file (cleanup) </li>
<li>
<code><a class="el" href="group__ClassTest.html#gadb786f2a6d34bd9cc6013fb973f18c13" title="Begin of a subtest with a given name. ">START_SECTION(name)</a></code><br/>
Start of a method test. If the name starts with '[EXTRA]' it does not have to match a methods name. </li>
<li>
<code><a class="el" href="group__ClassTest.html#ga123b967d91e583fb00b377328ba78b46" title="End of a subtest. ">END_SECTION()</a></code><br/>
End of a single test </li>
<li>
<code><a class="el" href="group__ClassTest.html#ga2491d6c44db439274567cea0a3e6f712" title="Print a status message. ">STATUS(message)</a></code><br/>
Shows a status message e.g. used to show the progress of a test preparations that take a while </li>
<li>
<code><a class="el" href="group__ClassTest.html#ga6dfb51fad5e70a1e970bc965094704e0" title="Skip the remainder of the current subtest. ">ABORT_IF(condition)</a></code><br/>
Skip remainder of substest if condition holds </li>
</ul>
<h3>Comparison macros</h3>
<ul>
<li>
<code><a class="el" href="group__ClassTest.html#ga28c3e33e75987220375e36d1480e26ec" title="Generic equality macro. ">TEST_EQUAL(a, b)</a></code><br/>
Tests if two expressions are equal </li>
<li>
<code><a class="el" href="group__ClassTest.html#gaf2f6f2b204d65f32c50a4411dc590fa3" title="Generic inequality macro. ">TEST_NOT_EQUAL(a, b)</a></code><br/>
Tests if two expressions are not equal </li>
<li>
<code><a class="el" href="group__ClassTest.html#gaa002aaeb2fa21d7052d360e0b0f08143" title="Floating point similarity macro. ">TEST_REAL_SIMILAR(a, b)</a></code><br/>
Tests if two real numbers are equal (within a margin) </li>
<li>
<code><a class="el" href="group__ClassTest.html#ga2d9f6a1d674b7bcab0c60a5711b8cb06" title="String equality macro. ">TEST_STRING_EQUAL(a, b)</a></code><br/>
Tests if <em>a</em> and <em>b</em> are equal as strings </li>
<li>
<code><a class="el" href="group__ClassTest.html#ga62434c58988651dd7d8c0a2748c8cc1d" title="String similarity macro. ">TEST_STRING_SIMILAR(a, b)</a></code><br/>
Tests if <em>a</em> and <em>b</em> are similar as strings - allowing numerical deviations and differing whitespaces </li>
<li>
<code><a class="el" href="group__ClassTest.html#gac41693dce4ec4b2684e1752a7554a086" title="Define the absolute tolerance for floating point comparisons. ">TOLERANCE_ABSOLUTE(double)</a></code><br/>
Sets the absolute difference allowed when testing floating point numbers </li>
<li>
<code><a class="el" href="group__ClassTest.html#ga4607c27748ec063217e2776c1bc5eab5" title="Define the relative tolerance for floating point comparisons. ">TOLERANCE_RELATIVE(double)</a></code><br/>
Sets the relative difference allowed when testing floating point numbers </li>
<li>
<code><a class="el" href="group__ClassTest.html#ga29e985393ac63f000023bf684f4d03fc" title="Exception test macro. ">TEST_EXCEPTION(exception, expression)</a></code><br/>
Tests if the expression throws the exception </li>
<li>
<code><a class="el" href="group__ClassTest.html#ga17a048abf673566b5b034f7d3c70bfd4" title="Exception test macro (with test for exception message). ">TEST_EXCEPTION_WITH_MESSAGE(exception, expression, message)</a></code><br/>
Tests if the expression throws the exception and if the exception has the message </li>
<li>
<code><a class="el" href="group__ClassTest.html#ga85ba35f6ee95e23e4cd008318495de54" title="File comparison macro. ">TEST_FILE_EQUAL(file, template_file)</a></code><br/>
Tests if two files are identical </li>
<li>
<code><a class="el" href="group__ClassTest.html#ga652ba7d73c732871aa4e9600444c9145" title="File similarity macro. ">TEST_FILE_SIMILAR(file, template_file)</a></code><br/>
Tests if two files are similar - allowing numerical deviations and differing whitespaces </li>
</ul>
<p>Do not use methods with side-effects inside the comparison macros i.e. *(it++). The expressions in the macro are called serveral times, so the side-effect is triggered several times as well.</p>
<h3>Temporary files</h3>
<p>You might want to create temporary files during the tests. The following macro puts a temporary filename into the string argument. The file is automatically deleted after the test.</p>
<p>All temporary files are validated using the XML schema,if the type of file can be determined by FileHandler. Therefor for each file written in a test NEW_TMP_FILE should be called. Otherwise only the last writen file is checked.</p>
<ul>
<li>
<code><a class="el" href="group__ClassTest.html#gadf364cea1469a3b7ebfde9e01332265f" title="Create a temporary filename. ">NEW_TMP_FILE(string)</a></code> </li>
</ul>
<h3>Tools for testing and checking your code.</h3>
<p>There are also some PHP tools for testing other tasks in the <code>tools/</code> directory. See <code>tools/README</code> for details!</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Testing the TOPP programs</h2>
<p>The abbreviation TOPP stands for The OpenMS Proteomics Pipeline, a collection of tools based upon the C++ classes in OpenMS. The TOPP tools are located in <code>source/APPLICATIONS/TOPP</code>.</p>
<h3>Creating a test</h3>
<p>The tests for a TOPP tool are simple commands which can be found in <code>source/TEST/TOPP/CMakeLists.txt</code>. To add a new test simply follow the examples given in that file. If a test needs suplementary input files, put these files in the same folder. The name of suplementary files has to begin with the name of the tested tool. All extensions but <code>.tmp</code> are possible.</p>
<h3>Building the tests</h3>
<p>In order to build the tests, execute the target "tests_build" (in VisualStudio based solution files, this target is available in the <code>source/TEST/OpenMS_tests.sln</code> solution, not in the <code>OpenMS.sln</code>) This will build the TOPP tools, UTILS and Unit-tests. Building the TOPP tools alone is not sufficient (you need FuzzyDiff - a UTIL to run the tests).</p>
<h3>Running the tests</h3>
<p>OpenMS uses CTest to run its tests. You can invoke the <code>ctest</code> executable in the OpenMS binary directory and it will run all tests (including TOPP tests). To run a specific test use the <code>ctest -R <testname></code>, e.g. <code>ctest -R TOPP_FileMerger</code> to run all FileMerger tests. You can add <code>-V</code> or <code>-VV</code> to ctest to make the output more verbose.</p>
<h3>Numerical inaccuracy</h3>
<p>The TOPP tests will be run on 32 bit and 64 bit platforms. Therefore a purely character-based comparison of computed and expected result files might fail although the results are in fact numerically correct - think of cases like <code>9.999e+3</code> vs. <code>1.0001e+4</code>. Instead we provide a small program <code>FuzzyDiff</code> as a UTIL. This program steps through both inputs simultaneously and classifies each position into 3 categories: <em>numbers</em>, <em>characters</em>, <em>whitespace</em>. Within each line of input, numbers are compared with respect to their ratio (i.e., relative error), characters must match exactly (e.g. case is significant) and all whitespace is considered equal. Empty lines or lines containing only whitespace are skipped, but extra linebreaks 'within' lines will result in error messages. You can also define a "whitelist" of terms, which makes FuzzyDiff ignore lines where these terms occur (useful for hardcoded filepaths etc). For more details and verbosity options, see the built-in help message and the source code.</p>
<h3>File name conventions for TOPP tests</h3>
<p>Each test relies on a number of files. These file should be named <code>source/TEST/TOPP/<toolname>_<nummer>_<name>.<extension></code>, where</p>
<ul>
<li>
<code><toolname></code> has the form <code>[A-Z][a-zA-Z]*</code>; this is the name of the TOPP tool </li>
<li>
<code><number></code> has the form <code>[0-9]+</code>; this is the running number of the test </li>
<li>
<code><name></code> has the form <code>[-_a-zA-Z0-9]+</code>; this should be a descriptive name (characters <code>_</code> and <code>-</code> are ok here, since <code><toolname></code> and <code><number></code> must not contain them) </li>
<li>
<code><extension></code>; this is the extension expressing the type of the data. </li>
</ul>
<p>The data files should be as small as possible, but not totally trivial.</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Is testing really necessary?</h2>
<p>Yes. Testing is crucial to verify the correctness of the library - especially when using C++. But why has it to be <em>so</em> complicated, using all these macros and stuff? One of the biggest problems when building large class frameworks is portability. C++ compilers are strange beasts and there is not a single one that accepts the same code as any other compiler. Since one of the main concerns of OpenMS is portability, we have to ensure that every single line of code compiles on all platforms. Due to the long compilation times and the (hopefully in future) large number of different platforms, tests to verify the correct behaviour of all classes have to be carried out automatically. This implies a well defined interface for all tests, which is the reason for all these strange macros. This fixed format also enforces the writing of complete class tests. Usually a programmer writes a few lines of code to test the parts of the code he wrote for correctness. Of the methods tested after the introduction of the test macros, about a tenth of all functions/methods showed severe errors or after thorough testing. Most of these errors didn't occur an all platforms or didn't show up on trivial input.</p>
<p>Writing tests for <em>each</em> method of a class also ensures that each line is compiled. When using class templates the compiler only compiles the methods called. Thus it is possible that a code segment contains syntactical errors but the compiler accepts the code happily - he simply ignores most of the code. This is quickly discovered in a complete test of all methods. The same is true for configuration dependend preprocessor directives that stem from platform dependencies. Often untested code also hides inside the <code>const</code> version of a method, when there is a non-const method with the same name and arguments (for example most of the <code>getName</code>) methods in OpenMS. In most cases, the non-const version is preferred by the compiler and it is usually not clear to the user which version is taken. Again, explicit testing of each single method provides help for this problem. The ideal method to tackle the problem of untested code is the complete coverage analysis of a class. Unfortunately this is only supported for very few compilers, so it is not used for testing OpenMS.</p>
<p>One last point: writing the test program is a wonderful opportunity to verify and complete the documentation! Often enough implementation details are not clear at the time the documentation is written. A lot of side effects or special cases that were added later do not appear in the documentation. Going through the documentation and the implementation in parallel is the best way to verify the documentation for consistence and (strange coincidence?!) the best way to implement a test program, too! </p>
</div></div><!-- contents -->
<HR style="height:1px; border:none; border-top:1px solid #c0c0c0;">
<TABLE width="100%" border="0">
<TR>
<TD><font color="#c0c0c0">OpenMS / TOPP release 1.11.1</font></TD>
<TD align="right"><font color="#c0c0c0">Documentation generated on Thu Nov 14 2013 11:19:25 using doxygen 1.8.5</font></TD>
</TR>
</TABLE>
</BODY>
</HTML>
|