Shotwell Vala Coding Conventions

Shotwell is written in Vala. The following guidelines are shaped toward describing our preferred coding style for Vala.

The goals of these coding conventions are consistency and readability for a team of coders, in the service of producing quality code. There are few hard-and-fast rules here. Use good judgment when stretching their boundaries or violating them outright. Ask if you’re unsure.

Formatting

Ordering

The members of each class should appear in the following order:

  1. consts
  2. enums
  3. inner classes
  4. static properties
  5. static fields (blocked in this order: public / protected / private)
  6. instance properties
  7. instance fields (blocked in this order: public / protected / private)
  8. signals
  9. constructors
  10. destructor (optional)
  11. methods

Basics

Right:

int x = get_x();
int y = get_y();

int width, height;
if (is_tall()) {
    width = 0;
    height = 100;
} else {
    width = 100;
    height = 0;
}

Right:

class Pair {
    int x;
    int y;

    public Pair(int x, int y) {
        this.x = x; // "this" needed for disambiguation
        this.y = y;
    }

    public void swap() {
        int t = x; // no "this"" here or on following lines
        x = y;
        y = t;
    }
}

Naming

Right:

Gtk.Window window;

Discouraged:

Gtk.Window w;

Braces

Right:

void foo() {
    for (int x = 0 ; x < 10 ; ++x) {
        ...
    }
}

Wrong:

void foo()
{
    for (int x = 0 ; x < 10 ; ++x)
    {
        ...
    }
}

Right:

if (x == 4) {
    ...
} else {
    ...
}

Wrong:

if (x == 4) {
    ...
} else ++y;

if (x == 4) {
    ...
} else
    ++y;

if (x == 4) {
    ...
}
else {
    ...
}

Right:

try {
    ...
} catch (Error e) {
    ...
}

Right:

return x;

Right:

return a + b;

Right:

if (x == 3)
   ++x;

if (x == 3) {
   ++x;
}

Wrong:

if (x == 3) ++x;

Spacing

Right:

a = x + y;

if (x == y)
    ...

Wrong:

a = x+y;

if (x==y)
    ...

Right:

++i;
x = j++;

Wrong:

++ i;
x = j ++;

Right:

left = !right;
stopped = !process.is_running();

Wrong:

left = ! right;
stopped = ! process.is_running();

Right:

int i[10];
x = i[4];

Wrong:

int i [10];
x = i [4];

Right:

int i = (int) f;

Wrong:

int i = (int)f;

* Keywords such as if, for, and while are followed by a space, then a left parenthesis.

Right:

if (x == 4)
    return;

Wrong:

if(x == 4)
    return;

if( x == 4 )
    return;

Right:

int count;
bool is_complete;
Window main_window;

Wrong:

int    count;
bool   is_complete;
Window main_window;

Right:

int add(int a, int b) {
    ...
}

int i = add(4, 5);

Wrong:

int add (int a, int b) {
    ...
}

int i = add ( 4, 5 );

namespace City {

class House {
    int xyz;
    ...
}

}

Comments

Acceptable:

int count; // number of widgets in the conglomeration

Better:

// number of widgets in the conglomeration
int count;

Wrong:

int count; //number of widgets in the conglomeration
int count;// number of widgets in the conglomeration

Language Features

Casting

if (obj is Gtk.Widget)
    // do something

try {
    ...
} catch (Error err) {
    bool is_cancelled = err is IOError.CANCELLED;
    bool is_ioerror = err is IOError;
}

Gtk.Widget? widget = obj as Gtk.Widget;
if (widget != null)
    widget.show_all();

Wrong:

Gtk.Widget widget = obj as Widget;
widget.show_all();

Right:

Gtk.Widget widget = (Gtk.Widget) obj;
widget.show_all();

Wrong:

Gtk.Widget widget = (Gtk.Widget) obj;
if (widget != null)
    widget.show_all();

Wrong:

assert(obj is Gtk.Widget);
Gtk.Widget widget = (Gtk.Widget) obj;

switch-case

Right:

switch (suit) {
    case Suit.SPADES:
        do_something();
    break;

    case Suit.HEARTS:
    case Suit.DIAMONDS:
        do_something_else();
        return;

    default:
        // do nothing for other suits
    break;
}

Wrong:

switch (suit) {
    case Suit.SPADES:
        do_something();
        break;

    case Suit.HEARTS:
        do_something();
    return;
    default:
    break;
}

Signals

Right:

public signal void plain_signal();

public virtual signal void virtual_signal() {
}

public signal void another_plain_signal();

Wrong:

public signal void plain_signal();
public virtual signal void virtual_signal() {}
public signal void another_plain_signal();

Right:

search_menu.activate.connect(on_search_menu_activated);

Right:

public signal void count_changed(int new_count);

protected virtual void notify_count_changed(int new_count) {
count_changed(new_count);
}

This allows for a subclass to override notify_count_changed and update its internal state before or after the signal has fired.

Properties

Right:

public int apple_count { get; private set; } // default set in constructor

public int orange_count { get; set; default = 0 }

public int banana_count {
    get {
        return (banana_list != null) ? banana_list.size : 0;
    }
}

private Gee.List<Banana>? banana_list = null;

Example (Geary):

private static Singleton? _instance = null;
public static Singleton instance {
    get {
        return (_instance != null) ? _instance : _instance = new Singleton();
    }
}

Closures (anonymous methods)

Right:

window.destroy.connect(() => { debug("destroyed"); });
window.draw.connect((ctx) => {
    debug("draw");
    ctx.clear();
});

Wrong:

window.destroy.connect((window_param) => {debug("destroyed");});
window.draw.connect((ctx) => {
    debug("draw");
});

Default arguments

Vala supports default arguments. As convenient as this feature can be, it can also introduce bugs.

Other language features

Valadoc

* If a symbol is an override or an interface implementation of a symbol documented in its parent class or interface, use the inheritDoc taglet:

/**
 * {@inheritDoc}
 */

Additional notes about the symbol should follow the taglet.

$ make valadoc

This will generate HTML in the valadoc/ directory.

Basics

* A protypical Valadoc for all types of code objects looks like this:

/**
 * A single line summary with a period.
 *
 * Longer (and, for simple code objects, optional) summary explaining the class/method/property in greater
 * detail. Like code lines, the summary lines should not exceed 100 characters per line.
 */

* Use HTML links whenever appropriate if the code is based off a specification or foreign API.

Classes

Each class should have a summary Valadoc. Place a single blank line between its Valadoc and the class declaration.

/** 
 * A representation of the IMAP APPEND command.
 *
 * See [[http://tools.ietf.org/html/rfc3501#section-6.3.11]] 
 */
public class Geary.Imap.AppendCommand : Command {

Other symbols

/**
 * Returns the direction of the overhead oscillating fnortiner.
 */
public bool clockwise { get; private set; }

public class Fnortiner {
    /**
     * Describes the {@link Fnortiner}’s position in the {@link Gizmo}.
     */
    public enum Position {
        /**
         * Indicates the {@link Fnortiner} is upside-down.
         */
        NORMAL,
        /**
         * Indicates the {@link Fnortiner} is inverted.
         */
        REVERSED
    }
}

Note how the containing class is linked in the Valadoc.

Apps/Shotwell/CodingConventions (last edited 2016-11-11 17:55:19 by JensGeorg)