Skip to content

Instantly share code, notes, and snippets.

Created November 18, 2013 12:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anonymous/7527033 to your computer and use it in GitHub Desktop.
Save anonymous/7527033 to your computer and use it in GitHub Desktop.
language filename contributors
D
learnd.d
/*TODO:
	* static variables and CTFE (also TLS)
	* delegates, function/delegate literals
	* DDOC sections, macros
	* value/alias template parameters
	* mixins
*/

// Single-line comments start with //

/* Multi-line comments look
like this. */

/+ Or they look like this. /++/ comments differ from /**/ comments in that they
can be nested. Which makes them the tool of choice for commenting out code. +/

// Import modules with 'import'.
import std.stdio; // std -> standard; io -> input/output
// All statements must end with a semicolon.

/* The program's entry point is a function called main. In its simplest form
it has no parameters and has a return type of 'void' which means it doesn't
return anything. */
void main()
{ // start of the function definition

int luckyNumber; // Declaring the variable 'luckyNumber' of type 'int'.
luckyNumber = 42; // Assigning a value.
int unluckyNumber = 13; // Declaring and assigning (initializing) in one step.

// Can use 'auto' instead of an explicit type when an initializer is present:
auto unluckyNumberAgain = unluckyNumber;

// Simple output is done via writeln ("write line") from std.stdio:
writeln("Your lucky number for today: ", luckyNumber);

///////////////////////////////////////
// Boolean Logic
///////////////////////////////////////

bool b = true;
b = !b; // logical negation => false
b = false || true; // logical or => true
b = false && true; // logical and => false

///////////////////////////////////////
// Integers
///////////////////////////////////////

// with sign
byte y; // 8 bits, aka 1 byte
short h; // 16 bits
int n; // 32 bits
long o; // 64 bits

/* For each signed integral type there is an unsigned one of the same size. The
names just have a "u" put in front. */
ubyte uy;
ushort us;
uint un;
ulong uo;

/* size_t has the same range as the address space,
i.e. unsigned 32 or 64 bits, depending on what machine you're compiling for. */
size_t st;

// Literals
n = 42; // decimal
n = 0x2A; // hexadecimal
n = 0b101010; // binary
// You can add underscores as separators for readability where you see fit.
o = 42_000_000_000; // easily recognizable as 42 billions
n = 0xFF_FF_F0_00; // 4 bytes, obviously
/* A literal's type defaults to int. When the value is too big for int, it's
long. You can use suffixes when you need to be explicit about a literal's
type. */
auto v1 = 42L; // long
auto v2 = 42U; // uint
auto v3 = 42UL; // ulong

// Arithmetic
n = 2 + 3; // addition => 5
n = 2 - 3; // subraction => -1
n = 2 * 3; // multiplication => 6
n = 2 / 3; // division => 0, because integer division rounds towards zero
n = 2 % 3; // modulo => 1
n = 2 ^^ 3; // exponentation => 8

n += 3; // shorthand for n = n + 3;
// You can do that with the other operators as well, of course.

// Comparison Operators
b = 3 == 2; // equal? false
b = 3 != 2; // not equal? true
b = 3 > 2; // greater than? true
b = 3 < 2; // less than? false
b = 2 <= 2; // less than or equal? true
b = 2 >= 2; // greater than or equal? true

///////////////////////////////////////
// Floating Point
///////////////////////////////////////

float f; // 32 bits
double d; // 64 bits
real r; // largest size the hardware supports, but at least 64 bits

d = 0.000_042;
d = 42e-6; // scientific notation

f = 1.0 / 10; // about 0.1
/* Otherwise similar to integer arithmetic. (Not specific to D, floating point
arithmetic in general has many subtle oddities; be aware.) */

///////////////////////////////////////
// Arrays
///////////////////////////////////////

int[] darr1; // a dynamic array of ints

darr1 = [1, 2, 3];
assert(darr1.length == 3);
/* assert is a builtin that throws an AssertError if the passed expression is
false. */

auto darr2 = darr1;
darr1[0] = 42; // Setting the first element to 42.
assert(darr2[0] == 42); // darr2 refers to the same data as darr1.

darr1 ~= 4; // append 4
assert(darr1 == [42, 2, 3, 4]);
assert(darr2 == [42, 2, 3]); // didn't affect darr2

/* The append operation copied darr1's data to a new location. darr1 no longer
refers to the same data as darr2: */
darr1[0] = 1;
assert(darr2[0] == 42);

// You can explicitly do such a copy:
auto darr3 = darr1.dup;
darr1[0] = 42;
assert(darr3[0] == 1);

// Quite different beasts are static (aka fixed-sized) arrays:
int[3] sarr1 = [1, 2, 3]; // a static array of 3 ints
// The length must be known at compile time.
// They are value types:
int[3] sarr2 = sarr1;
sarr1[0] = 42;
assert(sarr2[0] == 1);
// They cannot grow or shrink.
// You can get a dynamic array from a static one via the slicing operator:
int[] darr4 = sarr1[]; // darr4 refers to sarr1's data
/* Be careful with this, though. Static array variables live on the stack.
Dynamic views of their data are invalidated when the function returns. */

///////////////////////////////////////
// const And immutable
///////////////////////////////////////

const(int)[] carr; // The elements cannot be mutated through this variable.
immutable(int)[] iarr; // The elements cannot be mutated at all.
// Both unqualified (i.e. mutable) and immutable implicitly convert to const:
carr = darr1;
carr = iarr;

///////////////////////////////////////
// Text (Characters And Strings)
///////////////////////////////////////

char c = 'd'; // a UTF8 code unit
wchar wc = 'd'; // ("wide char") a UTF16 code unit
dchar dc = 'd'; // ("double wide char") a UTF32 code unit
// A dchar value is the same as the Unicode code point.

// Strings are arrays of immutable UTF code units. Same prefixes as with char.
string s; // string is an alias of immutable(char)[], i.e. they're synonymous
wstring ws; // ditto with wchar
dstring ds; // ditto with dchar

// Literals
c = 'a';
c = '\t'; // The usual escape sequences are understood.
assert("
" == "\n" || "
" == "\r\n"); // Actual newlines are allowed.
assert("" == "a\xC3\xA4"); // \x.. is a UTF8 byte
assert("" == "a\u00E4"); // \u.... is a 4 hexdigits Unicode code point
assert("" == "a\U000000E4"); // \U........ is a 8 hexdigits Unicode code point
/* Escape sequences are not recognized in 'WYSIWYG' (What You See Is What You
Get) string literals: */
assert(r"\n" == "\\n");
assert(`\n` == "\\n"); // alternative WYSIWYG syntax

// You can make your own aliases:
alias MyNameForByte = byte;
alias ubyte MyOtherNameForByte; // older, now somewhat less popular syntax

///////////////////////////////////////
// Control Structures
///////////////////////////////////////

if(false)
{
	writeln("I am never run.");
}
else if(false) // Can omit braces with single statements.
	writeln("I am also never run.");
else writeln("I print.");

switch(n)
{
	case 0: .. case 9: writeln("less than ten"); break;
	case 10: case 11: writeln("still not a dozen"); break;
	case 12: writeln("a dozen exactly"); break;
	default: writeln("a lot"); break;
}

// The following snippets all print "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ":

int i = 0;
while(i < 10)
	write(i++, ", "); // i++ increments i in-place, after using its value.
writeln();

int j = 0;
do
	write(j, ", ");
while(++j < 10); // ++j increments j in-place, before using its value
writeln();

for(int k = 0; k < 10; k++)
	write(k, ", ");
writeln();

foreach(k; 0 .. 10)
	write(k, ", ");
writeln();

///////////////////////////////////////
// Bitwise Operators
///////////////////////////////////////

ubyte u = 0b0000_0001;
assert(~u == 0b1111_1110); // bitwise negation
assert((0b1100 & 0b1010) == 0b1000); // bitwise AND
assert((0b1100 | 0b1010) == 0b1110); // bitwise (inclusive) OR
assert((0b1100 ^ 0b1010) == 0b0110); // bitwise XOR (eXclusive)
assert(1 << 2 == 0b100); // bitwise left shift (by 2)
assert(0b100 >> 1 == 0b10); // bitwise right shift (by 1)

///////////////////////////////////////
// Pointers
///////////////////////////////////////

int* p; // a pointer to (i.e. the memory address of) an int
void* pv; // a generic pointer to data of unknown type

// Use & to get a pointer to something:
int[2] stuff = [1, 2];
p = &stuff[0];
// Put a * in front to de-reference a pointer and retrieve the pointed-to value.
assert(*p == 1);

// Arithmetic
p += 1; // add the width of 1 int, i.e. 4
assert(*p == 2);

} // end of the main function

///////////////////////////////////////
// Functions
///////////////////////////////////////

/*
return type
|   function name
|   |     parameter type
|   |     |   parameter name
|   |     |   | */
int twice(int x)
{
	return 2 * x;
}
/* D's 'unittest' blocks are compiled in when you set some compiler switch
(-unittest for dmd, the reference compiler). They're run before the main
function. */
unittest
{
	assert(twice(7) == 14);
}

/* There are various attributes that can (and should) be put on functions:
'pure' guarantees that the function does not rely on or modify data other
than the passed arguments.
'nothrow' guarantees that the function does not throw any Exceptions.
'@safe' guarantees memory safety (e.g. forbids pointer arithmetic). */
int plus(int a, int b) pure nothrow @safe
{
	return a + b;
}
unittest
{
	/* There's an alternative function call syntax: UFCS, which stands for
	Uniform Function Call Syntax. It's "Uniform" because it looks like builtin
	properties and method calls.
	You put the first argument and a dot before the function name; the rest of
	the arguments go in the parentheses as usual: */
	assert(1.plus(2) == plus(1, 2));
}

/++ Documentation comments like this are part of the language (DDOC).

	Their left delimiters have an extra slash/asterisk/plus; i.e.:
	/// like this
	/** or like this */
	/++ or like this +/
+/
void demonstrateRefAndOut(int i, ref int r, out int o) pure nothrow @safe
{
	i = 2; // i is passed by value, so this only affects the local variable.
	r = 2; /* r is passed by reference, so this affects the variable at the call
		site, too. */
	
	/* The variable passed as o is reset to its initial value before passing it
	to the function by reference. */
	assert(o == int.init);
	o = 2;
}
unittest
{
	int i = 1;
	int r = 1;
	int o = 1;
	assert(o != int.init);
	
	demonstrateRefAndOut(i, r, o);
	assert(i == 1);
	assert(r == 2);
	assert(o == 2);
}

/* Functions can take compile time (template) parameters. The parameter list
goes before the list of runtime parameters. */
T templated(T)(T arg)
{
	// 'static if' is evaluated at compile time.
	/* 'is()' expressions are quite complex. This form simply tests if two
	types are the same. */
	static if(is(T == int)) return arg + 1;
	else static if(is(T == float)) return arg - 1;
	else return T.init;
}
unittest
{
	assert(templated(42) == 43); /* T is implicitly set from the argument.
		This is called Implicit Function Template Instantiation (IFTI). */
	assert(templated!(float)(42) == 41); // T is explicitly set to float.
	assert(templated!byte(42) == byte.init);
		// Can omit the parentheses with a simple single template argument.
}

/* An alternative implementation using template specializations instead of the
static if chain: */
T templated2(T : int)(T arg) {return arg + 1;}
T templated2(T : float)(T arg) {return arg - 1;}
T templated2(T)(T arg) {return T.init;}
unittest
{
	assert(templated2!int(42) == 43);
	assert(templated2!float(42) == 41);
	assert(templated2!byte(42) == 0);
}

/* Yet another variant, this time using template constraints.
Also demonstrating the 'auto' return type, meaning it's deduced from the
definition. */
auto templated3(T)(T arg) if(is(T == int)) {return arg + 1;}
auto templated3(T)(T arg) if(is(T == float)) {return arg - 1;}
auto templated3(T)(T arg) if(!(is(T == int) || is(T == float))) {return T.init;}
unittest
{
	assert(templated3!int(42) == 43);
	assert(templated3!float(42) == 41);
	assert(templated3!byte(42) == 0);
}

///////////////////////////////////////
// Structs And Classes
///////////////////////////////////////

// Structs are collections of data.
struct MyStruct
{
	int x, y;
	float z = 4.2;
}
unittest
{
	MyStruct s = MyStruct(42, 43); // Sets x and y, leaves z at the default.
	s.z = 44; // Access members with the dot operator.
	assert(s.x == 42 && s.y == 43 && s.z == 44);
	
	MyStruct* h = new MyStruct(42, 43);
		// 'new' constructs on the heap and returns a pointer.
	h.z = 44; // The dot operator automatically dereferences.
	assert(h.x == 42 && h.y == 43 && h.z == 44);
}

// Like functions, structs (and classes and interfaces) can be templated.
struct Rectangle(T)
{
	T width, height;
	
	/* Structs can have associated functions (methods).
	'const' guarantees that this method won't mutate the data. */
	auto area() const pure nothrow @safe
	{
		return width * height;
	}
}
unittest
{
	alias Rect = Rectangle!int;
	auto r = Rect(2, 3);
	assert(r.area() == 6);
}

/* Classes are similar to structs, but their natural habitat is the heap,
they are reference types, and they have inheritance. */
class A
{
	/* 'private' members are accessible from the current module only.
	They are non-virtual. */
	private string data;
	
	/* 'protected' members are also accessible from derived classes.
	'abstract' methods are to be overridden by derived classes. */
	abstract protected void appendFoobar() pure nothrow @safe;
	
	// They can still have implementations (to be used by the derived classes).
	abstract protected void prependFoobar() pure nothrow @safe
	{
		data = "Foobar" ~ data;
	}
	
	// 'public' members are accessible from anywhere.
	public bool startsWithFoobar() const pure nothrow @safe
	{
		return data[0 .. "Foobar".length] == "Foobar";
	}
	
	/* 'public' is the default, so you can omit the keyword.
	'final' methods cannot be overridden. They are non-virtual. */
	final endsWithFooar() const pure nothrow @safe
	{
		return data[$ - "Foobar".length .. $] == "Foobar";
	}
	
	// Classes need constructors to allow passing arguments on construction.
	this(string data) pure nothrow @safe
	{
		this.data = data;
	}
	this() {} // also allowing construction without arguments
}
unittest
{
	A a;
	assert(a is null);
	a = new A("..."); // Must construct with 'new'.
	assert(!a.startsWithFoobar());
	auto a2 = a;
	a2.prependFoobar();
	assert(a.startsWithFoobar()); // a and a2 refer to the same object.
}

class B : A // B inherits from (aka extends) A.
{
	override void appendFoobar() pure nothrow @safe
	{
		data ~= "Foobar";
	}
	
	override void prependFoobar() pure nothrow @safe
	{
		data = "!" ~ data;
		super.prependFoobar();
	}
	
	override bool startsWithFoobar() const pure nothrow @safe
	{
		return super.startsWithFoobar() && data["Foobar".length] == '!';
	}
}

/* A class can only inherit from one base class, but it can implement multiple
interfaces. */

interface I
{
	string shoot() pure nothrow @safe;
}

interface J
{
	string poot() pure nothrow @safe;
	
	// Interfaces can have final methods with implementations.
	final string root() pure nothrow @safe
	{
		return "/";
	}
}

class C : B, I, J
{
	string shoot() {return "pew pew";}
	string poot() {return "ppffrr";}
}

unittest
{
	I i = new C;
	assert(i.shoot == "pew pew");
	
	J j = new C;
	assert(j.poot == "ppffrr");
	assert(j.root == "/");
}

///////////////////////////////////////
// Templates
///////////////////////////////////////

// The template concept can be used independently from functions, etc.
template typeVariations(T)
{
	alias Const = const(T);
	alias Immutable = immutable(T);
}
unittest
{
	alias V = typeVariations!int;
	static assert(is(V.Const == const(int)));
	static assert(is(V.Immutable == immutable(int)));
}

///////////////////////////////////////
// enum
///////////////////////////////////////

// An enum is a list of static (compile time) values.
enum E {a = 1, b, c}
unittest
{
	assert(E.a = 1);
	// When you don't explicitly assign a value, it's the previous value + 1.
	assert(E.b == E.a + 1);
	assert(E.c == E.b + 1);
}

/* You can omit the enum name. The values are then put into the surrounding
scope. */
enum {a, b}
unittest {assert(b == a + 1);}

enum e = 42; // A single value is also called a "manifest constant".

Further Reading

http://dlang.org is the official website. When you have questions, don't fear asking in the beginner section of the forum.

The D Programming Language (TDPL) by Andrei Alexandrescu is the authoritative book on D.

D Programming Language Tutorial by Ali Çehreli is free.

@deflexor
Copy link

Very nice document, but it looks like static class members and functions not mentioned here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment