SDK Tools Guides

Home

Coding Conventions

These coding conventions are guidelines for developers creating MoSync code. These conventions are largely inspired by and derived from existing ones in well-known programming environments such as Java and SDL. As such, they shouldn't come across as exotic to any moderately experienced programmer.

[toc maxlevel=2;]

Header Files 

The #define Guard

All header files should have #define guards to prevent multiple inclusion. The format of the symbol name should be <PROJECT>_<PATH>_<FILE>_H_.

Header File Dependencies

Don't use an #include when a forward declaration would suffice.

Inline Functions

Define functions inline only when they are small, say, 10 lines or less.

Function Parameter Ordering

When defining a function, parameter order is: inputs, then outputs.

Names and Order of Includes

Use standard order for readability and to avoid hidden dependencies: C library, C++ library, other libraries' .h, your project's .h.

Scoping 

Nonmember, Static Member, and Global Functions

Prefer nonmember functions within a namespace or static member functions to global functions; use completely global functions rarely.

Local Variables

Place a function's variables in the narrowest scope possible, and initialize variables in the declaration.

Static and Global Variables

Static or global variables of class type are forbidden: they cause hard-to-find bugs due to indeterminate order of construction and destruction.

Classes 

Doing Work in Constructors

In general, constructors should merely set member variables to their initial values. Any complex initialization should go in an explicit Init() method.

Default Constructors

You must define a default constructor if your class defines member variables and has no other constructors. Otherwise the compiler will do it for you, badly.

Structs vs. Classes

Use a struct only for passive objects that carry data; everything else is a class.

Inheritance

Composition is often more appropriate than inheritance. When using inheritance, make it public.

Multiple Inheritance

Only very rarely is multiple implementation inheritance actually useful. We allow multiple inheritance only when at most one of the base classes has an implementation; all other base classes must be pure interface classes tagged with the Interface suffix.

Interfaces

Interfaces should be named using an I- prefix. Example: IMySexyInterface

Access Control

Make data members private, and provide access to them through accessor functions as needed. Typically a variable would be called mFoo and the accessor function getFoo(). You may also want a mutator function setFoo().

Declaration Order

Use the specified order of declarations within a class: public: before private:, methods before data members (variables), etc.

Write Short Functions

Prefer small and focused functions.

Other C++ Features

Reference Arguments

All parameters passed by reference must be labeled const.

Use of const

We strongly recommend that you use const whenever it makes sense to do so.

64-bit Portability

Code should be 64-bit and 32-bit friendly. Bear in mind problems of printing, comparisons, and structure alignment.

Preprocessor Macros

Be very cautious with macros. Prefer inline functions, enums, and const variables to macros.

Naming 

General Naming Rules

Function names, variable names, and filenames should be descriptive; eschew abbreviation. Types and variables should be nouns, while functions should be "command" verbs.

Type and Namespace Names

Type names start with a capital letter and have a capital letter for each new word, with no underscores: MyExcitingClass, MyExcitingEnum.

Variable Names

They start with a capital letter and have a capital letter for each new word, with no underscores. A m- prefix is used for member variables. A s- prefix is used for static variables. For instance: myExcitingLocalVariable, mMyExcitingMemberVariable, sMyExcitingMemberVariable

Constant Names

Use capitals and underscore as a separator: DAYS_IN_A_WEEK.

Function Names

Regular functions have mixed case; accessors and mutators match the name of the variable: myExcitingFunction(), myExcitingMethod(), getMyExcitingMemberVariable(), setMyExcitingMemberVariable().

Enumerator Names

Enumerators should be named either like constants or like macros: ENUM_NAME.

Macro Names

You're not really going to define a macro, are you? If you do, they're like this:  MY_MACRO_THAT_SCARES_SMALL_CHILDREN. 

Comments 

File Comments

Start each file with a copyright notice, followed by a description of the contents of the file.

Class Comments

Every class definition should have an /** accompanying comment */ that describes what it is for and how it should be used.

Function Comments

Every function should have a /** declaration comment */ which describes use of the function, using @param and @return syntax.

Variable Comments

In general the actual name of the variable should be descriptive enough to give a good idea of what the variable is used for. In certain cases, more comments are required.

Implementation Comments

In your implementation you should have comments in tricky, non-obvious, interesting, or important parts of your code.

Punctuation, Spelling and Grammar

Pay attention to punctuation, spelling, and grammar; it is easier to read well-written comments than badly written ones.

Formatting

Line Length

Each line of text in your code should be at most 80 characters long.

Preprocessor Directives

Preprocessor directives should not be indented but should instead start at the beginning of the line.

Class Format

Sections in public, protected and private order, each indented one space.

Indents and spaces

Inconsistent use of indents, tabs and spaces is a problem in much the same way as inconsistent naming is. Most text editors have the necessary options. For example, in Visual Studio, go Tools > Options > Text Editor > C/C++ > Tabs.
 
The following should apply to all MoSync code: one level of indention equals one tab. A tab is defined as the ASCII character \t. The actual screen size of the indents can thus be set by and for each user with no ill effects for others.

Syscalls

Syscalls are named using a ma- prefix. Only actual Syscalls and IOCTLs are named this way. Examples:
 
void maDisposeLayer(Handle layer);
void maSetMap(Handle layer, Handle srcMapResource, int destX, int destY);

Library functions

Library functions that are directly associated with the manipulation of some complex datatype (such as a struct) should be prefixed with the name of the type followed by an underscore, followed by the function name in camel case. Examples:

MAVec3_normalize(MAVec3* v);
MARect_containsPoint(const MAVec3* v, const MAPoint2d* p); 

Library functions that are not directly and strongly related to a datatype should be prefixed with an identifying name for the library, which should always contain an initial 'MA'. Examples:

MAMath_solveLinearSystem();
MAInet_sendMail();

Design Patterns

Syscalls and extensions

Syscalls and extensions constitute the lowest-level APIs available in MoSync. They are typically directly mapped to underlying platform features and are also subject to a number of restrictions:
 
The number of parameters is limited to four. If more information must be passed, the stack or struct pointers can be used.
Parameters cannot be function pointers. If a notification mechanism is required, one is required to make use of (custom) events.
The only allowed parameter types are primitive IDL types (see IDL documentation) and IDL structs that actually are declared in the relevant IDL file.
The only allowed return types are primitive IDL types.
MoSync memory cannot be allocated within syscalls, other than in the specific case of built-in or custom events.

Syscalls that manipulate objects/resources

Allocation, manipulation and deallocation of native objects (resources) is typically implemented by means of handles.
Typically, there is an maCreateX() function, which takes a placeholder handle to represent the allocated native object. Subsequent access to this object is provided through other syscalls that accept handles as their first parameter.
Finally, all objects are destroyed using maDestroyObject(). As an example, these are some functions that create and manipulate images:
 

void maCreateImageFromData(
in Handle placeholder,
in Handle data,
in int offset,
in int size
);
void maCreateImageRaw(
in Handle placeholder,
in MAAddress src,
in Extent size,
in int alpha
);
void maDrawImage(
in Handle image,
in int left,
in int top
);
void maDrawImageRegion(
in Handle image,
in MARect srcRect,
in MAPoint2d dstPoint,
in int transformMode
);

Asynchronous operations

Since MoSync doesn't support user-created threads, it is important to provide asynchronous interfaces to time-consuming native functionality such as network communication. Since syscalls can't accept function pointers, the central MoSync event system is used to provide progress notification. A few built-in event types are provided in the EVENT struct, but there's also a void* provided that can be used for custom events.

MoSync SDK 3.3
Copyright © 2013 MoSync AB
www.mosync.com