Skip to content
bilderbuchi edited this page Oct 3, 2011 · 40 revisions

The openFrameworks code style, modeled after the Qt style

See bottom for proposed changes and all modifications to the original Qt style.

Indentation

  • Currently OF is heavily biased towards tabs, is there something we could run as part of git commit that could convert tabs to spaces? Otherwise we stick with tabs. People contributing to OF should set their tab and indent width to four spaces.

Declaring variables

  • Declare each variable on a separate line

  • Avoid short (e.g. a, rbarr, nughdeget) names whenever possible

  • 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

       // Wrong
      int a, b;
      char *c, *d;
       // Correct
      int height;
      int width;
      char *nameOfThis;
      char *nameOfThat;
    
  • Variables and functions start with a lower-case letter. Each consecutive word in a variable’s name starts with an upper-case letter (camel case).

  • Avoid abbreviations

       // Wrong
      short Cntr;
      char ITEM_DELIM = '\t';
       // Correct
      short counter;
      char itemDelimiter = '\t';
    
  • Classes NEVER start with an upper-case letter.

Whitespace

  • Use blank lines to group statements together where suited

  • Always use only one blank line

  • Never use a single space after a keyword and before a curly brace.

       // Wrong
      if (foo) {
      }
       // Correct
      if(foo){
      }
    
  • For pointers or references, always use a single space between the type and * or &, and a space between the * or & and the variable name.

      char * x;
      const QString & myString;
      const char * const y = "hello";
    
  • Surround binary operators with spaces.

  • No space after a cast.

       // Wrong
      char* blockOfMemory = (char* ) malloc(data.size()); 
       // Correct
      char * blockOfMemory = (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){
      }
    
  • No Exceptions!: Function implementations and class declarations ALSO have the left brace on the same line as the start of the statement:

      static void foo(int g){
      	qDebug("foo: %i", g);
      }
       //
      class Moo{
      	public:
      };
    
  • Always use curly braces for all conditional statements and single line statements.

       // Wrong
      if (address.isEmpty())
      	return false;
    
       // 
      for (int i = 0; i < 10; ++i)
      	qDebug("%i", i);     
      
       // Correct
      if (address.isEmpty()){
      	return false;
      }
       //
      for (int i = 0; i < 10; ++i) {
      	qDebug("%i", i);
      }
    

Parentheses

  • Use parentheses to group expressions:

       // Wrong
      if (a && b || c) 
       // Correct
      if ((a && b) || c)
       // Wrong
      a + b & c
       // Correct
      (a + b) & c
    

Switch statements

  • The case labels are in the same column as the switch

  • Every case must have a break (or return) statement at the end or a comment to indicate that there’s intentionally no break, unless another case follows immediately.

      switch (myEnum){
      case Value1:
      	doSomething();
      	break;
      case Value2:
      case Value3:
      	doSomethingElse();
      	// fall through
      default:
      	defaultHandling();
      	break;
      }
    

Line breaks

  • Keep lines shorter than 100 characters; insert breaks if necessary.

  • Commas go at the end of a broken line; operators start at the beginning of the new line. An operator at the end of the line is easy to not see if your editor is too narrow.

       // Correct
      if (longExpression
      	+ otherLongExpression
      	+ otherOtherLongExpression){
      }
       // Wrong
      if (longExpression +
      	otherLongExpression +
      	otherOtherLongExpression){
      }
    

Inheritance and the virtual keyword

  • When reimplementing a virtual method, do not put the virtual keyword in the header file.

Current modifications to the Qt style

  • Removed "Q" class-name prefix, as it makes no sense for oF.
  • Curley Braces always open on the same line as statement, method, class.
  • No space between keyword and opening bracket.
  • No space between closing bracket and opening curly brace.
  • No capitalization of class names.

Preposed modifications to the Qt style

From the forum thread:

  • Break lines at 80, not 100 chars to ease side-by-side display (and work with IDEs with lots of stuff on the sides). Two 80-char text files just work out on my [bb] laptop. Maybe we drop the requirement if it messes up too much existing code.
  • Operators on wrapping lines at the end of the previous line. (just jrocha's taste, though, he says)
  • Guidelines for commenting/doxygen are needed! (Better do that later, and in a separate process)
  • Define a good comment: No redundancy; clearer code is better than comments to explain; if code is changed, keep the comments up-to-date; comment on the "why", not the "what".

Hot items for debate:

  • variable and comment alignment
  • usage of initialization lists

Important OF code style considerations.

###Clear vs Clever We prefer clear code to clever code - ideally it can be both.

###Use ofLog Never printf or cout

###Ternary operators Don't use ternary operators

###While loops Don't use while loops if possible

###Iterators vs for loops Use for loops for simple cases and iterators for more complex iteration

###C arrays vs vectors Use vectors unless there is a strong reason not to.

###Const correct / adding const We currently prefer not to have const added to old code. If adding it to new code, do it where it makes sense.

###Initialisation Lists We don't do this in the core. If you need it for initializing a reference then use it but otherwise do your initialization in the constructor.

###Initialisation member variables:

  • Always initialize variables with sensible starting values in the class constructor.
  • Pointers should be initialized to NULL.

###Assert Please don't use assert. We will find you and and make you pay! :)

###Constructors that take arguments:

  • Only do this if there is another way to set the starting params of a class.
  • We prefer setup or load functions for larger classes.
  • For classes like ofPoint constructor args make sense but also provide a set() method which does the same thing.

###//TODO: Please use //TODO: if you find something that needs fixing later eg: //TODO: fix this as its not returning a value.

###Class method order

  • We try and order the methods and member variables in the header file in the order that they should be used, and from least-technical to most-technical. For example:

    contstructor / destructor initialization and setup related functions core functionality operator overloading member variables

  • This ordering also applies to non-class headers. For example, a function taking (float x, float y) should precede an (ofPoint& point) function.

###Naming conventions:

  • we use the 'of' prefix for global functions, and class names. eg ofImage ofSetColor etc

  • we use non of prefix for class methods eg: ofImage::draw() instead of ofImage::ofDraw

  • methods that modify their object are named like ofColor::normalize(), while methods that return a copy are * named like ofColor::getNormalized

  • Most importantly - please look at how other similar things in of are named. eg if ofGet.... ofEnable... / ofDisable... Use your judgment to name things in a way that will be intuitive to others ( not just yourself ) based on the current OF api.

###Enums

  • If a function or method returns or takes as input an entry from a selection of options, use an enum instead of int. Make sure the function or method parameter is set to be of the enumtype and not int.
  • If the enum is tightly tied to a particular class, declare the enum inside the class instead of repeating the class name in the enum name

E.g.

    //--------------------------------------------------
    We don't do this:
    define OF_IMAGE_QUALITY_BEST    0
    define OF_IMAGE_QUALITY_LOW     1
    
    ofImage{
       void setQuality(int quality);
    };

    //--------------------------------------------------
    We do this:
    enum ofImageQualityType{
      OF_IMAGE_QUALITY_BEST,
      OF_IMAGE_QUALITY_LOW
    };

    ofImage{
      void setQuality(ofImageQualityType qualityType);    // use this
    };

    void testApp::setup(){
      myImage.setQuality(OF_IMAGE_QUALITY_BEST);
    }

##Finally - Important Considerations For Contributing Code.

  • Please test all the code you are submitting and all the use cases of it.

  • Include a complete list of changes in your pull request.

  • Always look at the diff tab of the pull request and check that nothing was unintentionally submitted.

  • Never do git add *. Always add files one at a time.

  • Don't mix formatting / code cleanup commits with commits for bugs and/or features. They will be rejected as it makes it very difficult to see actual api changes.

  • Have the code you write insert into the api as seamlessly as possible. If in doubt match the style / naming conventions of what is already there. Be a code ninja! Leave no trace :)