swuecho
11/21/2013 - 7:58 AM

d.html.markdown


language: D filename: learnd.d contributors:


/*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ä" == "a\xC3\xA4"); // \x.. is a UTF8 byte
assert("aä" == "a\u00E4"); // \u.... is a 4 hexdigits Unicode code point
assert("aä" == "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.