Skip to content

Instantly share code, notes, and snippets.

@swuecho
Forked from anonymous/d.html.markdown
Created November 21, 2013 07:58
Show Gist options
  • Save swuecho/7577577 to your computer and use it in GitHub Desktop.
Save swuecho/7577577 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.

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