Last update February 21, 2010

DProgramming Guidelines



Difference (last change) (Author, normal page display)

Changed: 215c215
enum ColorMode? { GRAYSCALE, RGB }; // right
enum ColorMode? { grayscale, rgb }; // right

This is an attempt to create a coherent set of programming guidelines for Phobos, and perhaps more projects written using the D programming language. Most of Phobos doesn't conform to those guidelines. Either Phobos should be adapted to fit these, or the guidelines should adapt to Phobos. Probably a little of both.

Table of contents of this page
Variables   
Types   
Derogation   
Functions   
General Rule   
Action functions   
Accessor functions   
Conversion Functions   
Overloading   
Arguments   
Bindings   
Abbreviations   

Variables    

Variable names can be nouns, adjectives, or third-person verbs with an object.

	string name;
	int accountNumber;
	bool dimmed;
	bool isCoherent;

You may use modal verbs (such as "can" and "should") for boolean values that control behaviour.

	bool shouldAnswer;

Types    

Types name should contain one noun, which may or may not be qualified by preceding it with an adjective.

	alias char[] MutableString; // right
	class Connection { }        // right

alias bool TrueOrFalse; // wrong (no nouns used) class Connect { } // wrong (no nouns used)

Types name should avoid redundancy.

	typedef int SerialNumber;        // right
	class Socket : Object { }        // right

typedef int SerialNumberInt; // wrong ('int' unnecessarily repeated) class SocketObject : Object { } // wrong ('object' unnecessarily repeated)

However, it is fine to repeat the base type name in the derived type name if the derived type is only a specialization having the same function, and when it absence might encourage ambiguity or loss of intent:

	class RemoteObject : Object { }  // right
	class TcpSocket : Socket { }     // right
	class ConnectAction : Action { } // right

class RemoteThing : Object { } // not good class TcpConnector : Socket { } // not good class ConnectVerb : Action { } // not good

Derogation    

Some standard types in C do not respect the rules enumerated above, but are still acceptable when they do not have their equivalent int D. Types such as `size_t` and `ptrdiff_t` are acceptable, but `wchar_t` should be avoided (use `wchar` or `dchar` instead).

Functions    

General Rule    

Functions should start with a lowercase letter; each following word should be capitalized. Avoid cryptic or hard-to-pronounce abbreviations in function names.

Action functions    

Functions performing a transforming action should start with a verb.

	void sort(List subject, Predicate lessThan); // right
	void moveTo(Rect subject, Point pos);        // right
	void popFront(Range subject);                // right

Functions not changing the state of their arguments should use a past-participle or an adjective describing the returned value. They can also be nouns part of an implicit sentence "[noun] of [arguments]". Avoid making them properties.

	List sorted(List subject, Predicate lessThan); // right
	Rect movedTo(Rect subject, Point pos);         // right
	real sin(real angle);                          // right, reads "sine of angle"

@property List reversed(List subject); // wrong

Functions evaluating a boolean characteristic should either start with the prefix "is" or have the property attribute. This makes them distinguishable from the above category.

	bool isSorted(List subject, Predicate lessThan); // right
	@property bool sorted(); // right

Accessor functions    

Accessor functions can be nouns, adjectives, or third-person verbs with an object. They should have the @property attribute and return the value for the aspect they give you access to.

	@property {
		string name();      // right
		bool enabled();     // right
		bool showsRegion(); // right
	}

Setter and getter should have the same name. This allows the property syntax to be used when accessing the value:

	@property {
		void value(string newValue); // setter
		string value();              // getter
	}

// Property syntax: value = "hello"; string n = value;

Boolean properties do not need to start with "is", but may use "has" or a modal verb such as "can" and "should".

	@property {
		bool enabled();     // right
		bool empty();       // right
		bool shouldWait();  // right
		bool hasFuel();     // right
	}

@property { bool isEnabled(); // avoid, "is" is unnecessary bool isEmpty(); // avoid, "is" is unnecessary bool wait(); // wrong bool fuel(); // wrong }

enabled = true; bool e = enabled;

Avoid the unnecessary prefix "get" or "set" in front of function names. If you can't avoid them, don't use the @property attribute on them:

	string getTitle();              // avoid
	void setTitle(string newTitle); // avoid

@property string getTitle(); // wrong @property void setTitle(string newTitle); // wrong

You should still use "get" for getters that return data through function arguments. Such getter functions should use "out" arguments to make clear which arguments return values. Use "set" for setters taking multiple arguments.

	void getStatistics(out int visitCount, out int[] visitPerDay); // right
	void setRatio(float widthFactor, float heightFactor); // right

You should use modal verbs (such as "can" and "should") to clarify a meaning when necessary.

	@property {
		bool canGoBack();          // right
		void canGoBack(bool flag); // right
	}

When an accessor performs an expensive operation, it is often preferable to make it an action function through the addition of a verb:

	uint computeAverage();    // right
	uint walkLength();        // right
	@property uint average(); // wrong if getting the average is expensive
	@property uint length();  // wrong if getting the length is expensive

[Note: perhaps we should have a standard verb for this.]

Conversion Functions    

Functions that convert from one type to a given target type should begin with "to" and be followed by the target type name. The type name should capitalized according to function capitalization rules:

	string toString(Object o);

The target type can also be expressed as a template argument. The function is then simply named "to" and the template argument carries the type.

	T to(T)(Object o);

Overloading    

Functions with the same name but different argument types are overloaded. Functions should be part of the same overload set if they all perform the same basic task using different arguments.

Function names should generally not contain information expressed by the type of their argument, this information is advertised in the function signature:

	float truncate(float value);      // right
	float altitude(Plane plane);      // right, reads "altitude of plane"

float truncateFloat(float value); // wrong float planeAltitude(Plane plane); // wrong float altitudeOfPlane(Plane plane); // wrong

Arguments    

Function arguments are variables and should start with a lowercase letter and each successive word should start with a capital letter.

Arguments should have a clear, descriptive name of how they're going to be used. Avoid insignificant names such as one-letter names, or hard-to-decipher abbreviations.

	void send(string message, IpAddress? destination); // right

void send(string messageString, IpAddress? destinationAddress); // wrong void send(string str, IpAddress? ip); // wrong void send(string m, IpAddress? d); // wrong

Bindings    

When writing bindings for code in other languages or system functions, types, variables, constants, functions, and arguments can keep their original names:

	extern (C):
	typedef int pthread_t;                         // acceptable

pthread_t pthread_self(); // acceptable int pthread_equal(pthread_t t1, pthread_t t2); // acceptable

Wrapper classes and functions written around the direct bindings should follow the D conventions however.

	class Thread
	{
		private pthread_t threadId;   // good

static Thread self(); // good bool opEquals(Thread other); // good }

Unless they are private, direct access to non-D functions should be kept in separate modules from the D wrappers. This clean separation avoid mixing programming styles the two equivalent APIs and their different programming styles.

Abbreviations    

Common abbreviations (such as ASCII, PDF, RGB, or XML) are allowed, but should be capitalized as regular words:

	byte[] toAscii();                   // right
	char[] xmlSerialization();          // right
	class PdfDocument? { }               // right
	enum ColorMode? { grayscale, rgb };  // right

byte[] toASCII(); // wrong char[] XMLSerialization(); // wrong class PDFDocument { } // wrong


FrontPage | News | TestPage | MessageBoard | Search | Contributors | Folders | Index | Help | Preferences | Edit

Edit text of this page (date of last change: February 21, 2010 15:25 (diff))