QET Coding style

Inspired from http://qt-project.org/wiki/Qt_Coding_Style

This is an overview of the coding conventions to be used when writing code for the QElectroTech project.

Indentation and alignment

  • real tabs for indentation, spaces for alignment!
  • one real tab is one 0x09 ASCII character, not a bunch of 0x20 spaces.
  • It is strongly recommended to work with an editor that highlights differences between spaces and tabs to avoid shame and mockery.
  • Use one tab character to mark each semantic depth increment.
  • Indentation = tabs: never use spaces at the beginning of a line
  • Do not ask how long a tab should be: configure your editor so it fits your taste
  • You may also use tabs within long conditions or to make long function calls more readable:
    void Class::methodName(const QString &string, const QString &suffix = QString()) {
    	int dummy_return_value = -1;
    	if (
    		string.length() < 567 &&
    		!suffix.isEmpty() // forget the dummy code, notice the indentation
    	) {
    		dummy_return_value = string.lastIndexOf(
    			QRegExp("chabadabada", Qt::CaseInsensitive),
    			42
    		);
    	}
    	return(dummy_return_value);
    }
  • Alignment = spaces: Never use tabs anywhere else than at the beginning of a line
  • You may use spaces to align e.g. similar function arguments; for instance:
    	object -> method(arg1,      arg2); // spaces are used to align arg2 and argument2
    	object -> method(argument1, argument2);

    However, beware of this habit since it always ends up with you having to realign many semantically-untouched lines. The main conseqence of this kind of operations is that basic svn diff, such as those sent by mail after each commit, get less readable. In case you fell in the trap, the -b or --ignore-space-change option exposed by both diff and svn diff should come useful.

Encoding

Regarding indentation, some may argue that horizontal tab is considered a control character and thus not a printable one. Feel free to discuss that topic on a rainy sunday during a power outage, but the QElectroTech project accepts that non-printable character in its code. However, we *flee* non-ASCII characters: insert Unicode characters using HTML entities such as &#xHH; or octal notation such as \0321, but strive on remaining within the warm and well-known ASCII table. That should spare you some compilation/portability issues.

End of lines

Unix-style only, Unix-style everywhere: lines should be separated with a LF (Line Feed, the Unix way) character, not a CR (Carriage Return, the Mac way) nor a CRLF (the Windows way). The last line of a file should also end with a LF.

Declaring variables

  • You may declare several variables on the same line, especially if their use or meaning are related.
  • Avoid short or meaningless names (e.g. “a”, “rbarr”, “nughdeget”); prefer proper, longer names, e.g. conductor_text instead of ctext or ct – the name of a variable should reflect its usage and content.
  • Single character variable names are only okay for counters and temporaries, where the purpose of the variable is obvious
  • Wait when declaring a variable until it is needed, unless you think it really deserves, for clarity reasons, to be declared next to another specific one.
  • variables have no uppercase characters at all and feature underscores to achieve readability, e.g. conductors_count
  • private and protected attributes should end with an underscore, e.g. font_size_
  • While this underscore habit is remotely inspired from the hungarian notation, the QElectroTech project does not use it at all. So avoid suffixes and modifiers such as m_ / g_ / s_ / l_ …
  • rules for public attributes are rather undefined because their usage is discouraged.
  • avoid abbreviations:
    	// Wrong
    	short Cntr;
    	char ITEM_DELIM = '\t';
    	int ConductorsCount;
     
    	// Correct
    	short counter;
    	char item_delimiter = '\t';
    	int conductors_count;
  • classes always start with an upper-case letter. Classes that have no luck to be reused in a common library start with 'QET' (e.g. QETApp, QETDiagramEditor, QETElementEditor).
  • Abbreviations are NOT camel-cased (e.g. QETApp)

Whitespace

  • Use blank lines to group statements together where suited
  • Always use only one blank line
  • Never use spaces right after an opening parenthese or before a closing one: if (condition), not if ( condition )
  • Never let spaces at the end of a line.
  • Always use a single space between // and the actual comment
  • Always use a single space after a keyword and before a curly brace:
    	// Wrong
    	if ( foo ) {
    	}
    	// Wrong
    	if(foo){
    	}
     
    	// Correct
    	if (foo) {
    	}
  • For pointers or references, always use a single space between the type and ‘*’ or ‘&’, but no space between the ‘*’ or ‘&’ and the variable name.
    	char *x;
    	const QString &my_string;
    	const char * const y = "hello";
  • Surround binary operators with spaces.
  • Especially, surround the → operator with spaces:
    	my_object -> interestingMethod();
  • No space after a cast.
  • Avoid C-style casts when possible: C++ provide static_cast, dynamic_cast, const_cast, reinterpret_cast, Qt provides qobject_cast, qgraphicsitem_cast, etc.
    	// Wrong
    	char* blockOfMemory = (char* ) malloc(data.size());
     
    	// Correct
    	char *block_of_memory = reinterpret_cast<char *>(malloc(data.size()));

Braces

  • As a base rule, the left curly brace goes on the same line as the start of the statement:
    	// Wrong
    	if (codec)
    	{
    	}
     
    	// Correct
    	if (codec) {
    	}
  • Exception: constructors with attribute initialization statements:
    	VeryInterestingClass::VeryInterestingClass() :
    		simple_attribute(42),
    		complicated_attribute(43)
    	{
    		// more complex code
    	}
  • Conditions: either the condition is simple enough to fit on a single line, or you must use braces:
    	// Correct: simple conditions that fit on a single line are ok
    	if (things -> areNotLikeExpected()) return;
     
    	// Correct: otherwise, use braces
    	if (things -> areNotLikeExpected()) {
    		// you can even use them when there is only one statement... future
    		// modifications will result in commit diff which are easier to review
    		doSomeStuff(foo, bar, yadda_yadda);
    		doSomethingElse(bar, foo, yadda_yadda);
    	}
    	else {
    		// another tip: "} else {" statements are allowed, but splitting the else
    		// part this way make it easier to comment and/or remove
    		beginUsualStuff(foo, bar, yadda_yadda);
    		beginUsualStuff(foo, bar, yadda_yadda);
    		beginUsualStuff(foo, bar, yadda_yadda);
    	}
     
    	// Wrong: two lines, no braces
    	if (my && shiny && condition || evaluates ^ to_true)
    		return -1;
     
    	// In case of doubt: use braces.

Line breaks

  • What does “fit on a single line” mean? The QElectroTech project does not enforce the good old 80 characters limitation (thus avoiding questions such as “How many chars/spaces is a tab?”); just be reasonable, despite you just bought two 26“ wide screens… In case you wonder, Qt coding guidelines say “100 characters”.

Parentheses

  • Use parentheses to group expressions in order to avoid ambiguous writings: when reading your code, nobody should ever have to think “f*ck, what are the precedence rules again?”:
    	// Wrong
    	if (a && b || c)
     
    	// Correct
    	if ((a && b) || c)
     
    	// Wrong
    	a + b & c
     
    	// Correct
    	(a + b) & c

Switch statements

  • oh, yeah, switch statements. Well. Err. How to say. Surely there are switch statements in QElectroTech… like, 24 of them in the whole code. Clearly, we tend to prefer if statements, which are easier to read and less error-prone.

Declaring methods

  • Methods are of course declared in .h files, and most often implemented in .cpp files;
  • getters/setters follow the foo()/setFoo() pattern, not getFoo()/setFoo()
  • Methods begin with a lowercase character, never feature any underscore and are camel-cased, e.g. removeConductor()
  • We do not duplicate Doxygen documentation:
    • Doxygen documentation should go in the header for abstract methods (i.e. “this method is abstract and shall be reimplemented to do this and that”)
    • Doxygen documentation should go above the implementation for regular methods
  • Doxygen comments are started with /** and ended with */
  • intermediate lines do not feature extra * (did you know? they are optional)
  • intermediate lines are typically indented with tabs
  • once this semantic indentation is applied, you can switch to spaces e.g. to please Doxygen list parser:
	/**
		Represents the kind of a particular conductor:
		  * Simple: no symbols, no text input
		  * Single: singleline symbols, no text input
		  * Multi: text input, no symbol
	*/
	enum ConductorType { Simple, Single, Multi };

What to commit

  • Each commit should represent either a complete feature or an atomic modification that will lead to that feature
  • The trunk will of course end regularly broken – this does not justify committing very bad code
  • Do not commit commented out code (aka ”zombie code“) – Subversion and other VCS solutions are meant to avoid that by keeping the whole code history so that deleted code is never considered lost.
  • Do not commit your name or trigram in a comment – VCS solutions track the author of each line (e.g. svn annotate)
  • Your commit should have a short, meaningful commit message: use English, remain formal (i.e. avoid things like “Committed that long-waited feature, WOUHOU!”), describe what the commit changes; avoid generic, meaningless sentences such as “minor change” or “bug fix”, since almost every commit is just a minor change or a bug fix.

TODO Describe conventions to follow when declaring a class.

Print/export