handson-dlang/hands-on_dlang.md
2018-04-13 15:02:06 +02:00

323 lines
8.4 KiB
Markdown

# Hands-On DLang
## Setup
### Installing DMD and DUB
#### OS X
##### Installing with Homebrew (recommended)
```bash
brew install dmd
brew install dub
```
##### Installing locally using the install script
```bash
curl -fsS https://dlang.org/install.sh | bash -s dmd
echo "~/.dlang/dmd-2.079.0/activate" >> ~/.profile # Add dmd and dub to PATH on starting a bash shell
```
##### Installing using the installer
* Download http://downloads.dlang.org/releases/2.x/2.079.0/dmd.2.079.0.dmg.
* Open `dmd.2.079.0.dmg`
* Run `DMD2.pkg` (you might need to activate the “allow installing applications from unverified developers” option in your security settings) and install with the default settings.
#### Windows
* Download http://downloads.dlang.org/releases/2.x/2.079.0/dmd-2.079.0.exe.
* Run `dmd-2.079.0.exe` and install with the default settings (this will also install Visual Studio if you do not have it installed yet).
### Recommended editor setup
Visual Studio Code is the recommended editor, because it has the best D integration at the moment.
If you want to use another editor or IDE, that is perfectly fine.
However, instructions will only be provided for Visual Studio Code.
#### Installation of Visual Studio Code
Download and install Visual Studio Code from here: https://code.visualstudio.com/. OS X users can also install it using Homebrew:
```bash
brew tap caskroom/cask
brew cask install visual-studio-code
```
#### Extension setup
* Open the Extension view in the sidebar:
|Operating system|Shortcut |
|----------------|---------|
|OS X |⌘ + ⇧ + X|
|Windows |⌃ + ⇧ + X|
* Install the extension “D Programming Language (code-d)” (requires that git is installed).
* Restart Visual Studio Code.
## Basics
### Hello World
```D
import std.stdio;
void main() {
writeln("Hello World");
}
```
### Imports and modules
D has the concept of _modules_ and _packages_.
By importing a certain module with the `import` statement, all public symbols from module become available.
The standard library, called Phobos, is located in the `std` package.
E.g. in order to import the `file` module from Phobos, you would write:
```D
import std.file;
```
#### Selective imports
It is possible (and often good style) to import symbols selectively from a module:
```D
import std.stdio: writeln, writefln;
```
#### Scoped imports
It is not necessary to place imports at the beginning of a file.
They can be located anywhere in the code.
If they appear inside a certain scope (delimited by braces), the imported symbols are only available inside that scope.
Here is an alternative version of the hello world program:
```D
void main()
{
import std.stdio: writeln;
writeln("Hello World");
}
/* writeln is not available outside of the main function */
```
#### Imports match files and directories
The module system is entirely based on files.
E.g. `my.thing` refers to a file `thing.d` in the folder `my/`.
### Basic Types
D has the following basic types:
| Datatypes | Size |
| ------------------------------- | ------------------------------------------------------------ |
| `bool` `byte`, `ubyte`, `char` | 8-bit |
| `short`, `ushort`, `wchar` | 16-bit |
| `int`, `uint`, `dchar`, `float` | 32-bit |
| `long`, `ulong`, `double` | 64-bit |
| `real` | >= 64-bit (generally 64-bit, but 80-bit on Intel x86 32-bit) |
`char` represents UTF-8 characters, `wchar`represents UTF-16 characters, and `dchar` represents UTF-32 characters.
#### Type conversion
For integer types, automatic type conversion is only allowed if no precision is lost (e.g. `int` to `long`).
All conversion between floating point types are allowed (e.g. `double` to `float`).
Manual type conversion is achieved with the `cast` expression:
```D
long a = 1;
int b = cast(int) a;
```
#### Type properties
All types have a property `.init` to which variables of that type are initialized, if they are not initialized explicitly.
For integer types, this is `0` and for floating point types it is `nan`.
Every type also has a `.stringof` property which yields its name as a string.
Integer types have some more properties:
| Property | Description |
| -------- | ----------------------------------- |
| `.max` | The maximum value the type can hold |
| `.min` | The minimum value the type can hold |
And so do floating point types:
| Property | Description |
| ------------- | ----------------------------------------------------------- |
| `.max` | The maximum value the type can hold |
| `.min_normal` | The smallest representable normalized value that is not `0` |
| `.nan` | NaN value |
| `.infinity` | Infinity value |
| `.dig` | number of decimal digits of precisions |
| `.mant_dig` | number of bits in mantissa |
| … | |
#### Indexing
For indexing, usually the alias type `size_t` is used, which is large enough to represent an offset into all addressable memory.
### Variable declarations
Variables are declared by writing the type followed by the variable name:
```D
int myVar;
```
They can also be explicitly initialized:
```D
int myVar = 42;
```
It is also possible to declare several variables at once:
```D
int myVar, someOtherVar;
```
D has automatic type deduction, so when explicitly initializing a variable, it is not necessary to mention the type.
Instead we can use the `auto` keyword:
```D
auto myVar = 42;
```
Here is a combination of the above notations:
```D
auto myInt = 42, myFloat = 4.2f;
```
### Functions
The basic syntax for functions is very similar to C:
```D
int add(int lhs, int rhs) {
return lhs + rhs;
}
```
#### Return type deduction
A functions return type can be defined to be `auto`.
In this case, the return type will be infered.
Multiple return statements are possible, but must return compatible types.
```D
auto add(int lhs, int rhs) { // returns `int`
return lhs + rhs;
}
auto lessOrEqual(int lhs, int rhs) { // returns `double`
if (lhs <= rhs)
return 0;
else
return 1.0;
}
```
#### Default arguments
Those also work the same as in C and other languages:
```D
void plot(string msg, string color = "red") {
/* ... */
}
plot("D rocks");
plot("D rocks", "blue");
```
#### Local functions
It is possible to define functions locally (even inside other functions).
Those functions are not visible outside their parents scope.
```D
void fun() {
int local = 10;
int fun_secret() {
local++; // that's legal
}
/* … */
}
static assert(!__traits(compiles, fun_secret())); // fun_secret is not visible here
```
### Control flow
#### if…else
Very similar to how it is defined in other languages:
```D
if (a == 5) {
writeln("Condition is met");
} else if (a > 10) {
writeln("Another condition is met");
} else {
writeln("Nothing is met!");
}
```
#### switch…case
Also very similar to how it is defined in other languages, but for it works for integer types, bools and strings (which will be covered later).
```D
string myString;
/* … */
switch(myString) {
case "foo":
writeln(`Cool, myString was "foo"`);
break;
default:
writeln("Meh, myString was something boring");
break;
}
```
For integer types, it is also possible to define ranges:
```D
int c = 5;
switch(c) {
case 0: .. case 9:
writeln(c, " is within 0-9");
break; // necessary!
case 10:
writeln("A Ten!");
break;
default: // if nothing else matches
writeln("Nothing");
break;
}
```
#### Loops
`while`-, `do`…`while`- and classical `for`-loops all work the same as in C++/Java etc.
##### Breaking out of outer loops
As usual, you can break out of a loop immediately by using the `break` keyword. Additionally, you can also break out of outer loops by using labels:
```D
outer:
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 5; ++j) {
/* … */
break outer; // breaks out of the outer loop
}
}
```