Learn to Code via Tutorials on Repl.it!

← Back to all posts
A Beginner's Crash Course on Dlang
DungeonMaster00 (189)

A Beginner's Crash Course on Dlang

Unfortunately for us, it is hard to make a D repl. Luckily, @CodeLongAndPros and @StudentFires released a template for D repls. The example at the bottom uses the Dlang template.

This tutorial will give you the basics of D in one place.

I will be improving this tutorialta over time.

Also, I will be referring to Dlang as it's shorter term, D throughout this crash Course.


C# Dash tutorials

Scratch Tutorials


Change log (since posting)

NOTE: This does not count minor changes.

  • Somewhere around Aug. 3-4, 2020: Fixed some typos, made a Unicode in D section, and updated the section on Classes.
  • Aug. 6, 2020: Added a section on exception handling.
  • Aug. 6, 2020: Split the "Important data types and variables" section into two sections.
  • Aug. 7, 2020: Added a section on imports.
  • Aug. 7, 2020: Updated the operators section and added a section on structs
  • Aug. 19, 2020: Added a thing on loop labels to the Loops section
  • Sep. 4, 2020: Changed name from "A Crash Course on Dlang" to "A Beginner's Crash Course on Dlang"

Anyways...

LET'S GET STARTED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

THE FIRST D TUTORIAL ON REPL.IT (over 600 lines of markdown)!!!!!

Basic Info

Thanks to @StudentFires for suggesting somethings to say here.

  • D is a programming language that is similar to C and C++
  • Full Unicode support
  • Every regular line must end with a semicolon (unless, of course, it's just braces for functions and stuff)
  • File extension is .d
  • Compiled language
  • Multi-paradigm
  • Garbage collected (similar to java)
  • Has the signature sonic-the-hedgehoglike speed of C and C++ (slower unfortunately), except it's way easier to use


Image from dlang.org.

Image from tour.dlang.org.


Comments

A single line comment in D starts with //. Multi line comments start with /* and end with */

// Single line comment Anything after the // on the same line is not run.

/*
Multiline comment.
Extends over multiple lines duh.
You can use these to make code not run without deleting it.
These are really cool.
But it must always end with:
*/

How and when to use comments depend on who you ask. I say to use single line comments to sort of divide your code into sections and to use multiline comments to prevent errory/buggy code from being run. But it's your choice on how to use comments or to use them at all.

Companies usually put comments at the top of a file for copyright notices.


Hello World!, Your first D program

You all know programming tradition.

We usually print something similar to Hello World! in the console.

I follow programming tradition in this tutorial

To print something to the console, we use writeln. Here is an example:

import std.stdio: writeln;

void main() {
    writeln("Hello World!");
}

/*
The code above outputs the following:

Hello World!
*/

Let's break that down.

The import statement, in this case, imports writeln from std.stdio. You can have import statements anywhere in your code, but it's recommended that you have them at the top of the file.

void main() acts as an entry point for the program

writeln will print something to the console.

You also have write that does not have any newlines.

Example:

import std.stdio: write;

void main() {
	write("Now ");
	write("goodbye world...");
}

/*
The code above outputs the following:

Now goodbye world...
*/

You also can print multiple things, including variables (explained later.)


Basic Data types

There are tons of data types in D, here are some basic ones:

  • bool - A boolean value (either true or false)
  • int - A signed 32-bit integral value
  • float - 32-bit floating point value
  • double - 64-bit floating point value
  • char - UTF-8 code unit (character)

NOTE: String is a special array type. You can learn more about them here.


Variables

Variables are values stored under a name. Like C, C++, and C#, you have to define the data type for the variable.

It follows the following order:

<data_type> <variable_name> = <value>;
// You can also define variables to be used later
<data_type> <variable_name>;

Example:

int variable = 5;

Follow these rules when naming variables

  • NEVER put spaces in variable names
  • The variable name cannot start with a number
  • Don't make it a D keyword
  • Besides numbers and letters, only put underscores in variable names.

readln, Capture user input

If you want to make your program interactive, then use readln.

You usually store it in a string variable.

Example:

import std.stdio: writeln, readln;
// Yes, you can import multiple things easily by using a comma in between functions

void main() {
	writeln("Enter your name.");
	string name = readln();
	// Don't forget that you can print multiple things, including non-string and non-char variables, with a comma.
	writeln("Your Sithlord name is:\n\nDarth ", name);
}
/*
Sample Output:

Enter your name.
Link
Your Sithlord name is:

Darth Link
*/

This is making good use of the string type.


Arrays

Arrays are basically variables that store multiple pieces of data.

Each piece of data in an array is an index. Indices start at zero and the index number increases by one for each index. That's how you can tell different pieces of data in an array apart.

There are two kinds of arrays, static and dynamic.

Static arrays

Static arrays cannot be changed.

This can be used as a list for every possible item that can be in the inventory

They are created like the following:

string every_item[5] = ["sword", "dagger", "shield", "healing potion", "poison bottle"];
// You can also print them like following
writeln("Last of possible items are: ", every_item[4]);
/*
The code above outputs the following:

Last of possible items are: poison bottle
*/

The array is static if you have a length inside the brackets

Dynamic arrays

Dynamic arrays can be changed after being run.

You can make one by removing the array length.

It's handy for a game inventory.

Example:

string inventory[] = ["sword", "shield", "healing potion"];
writeln("You have:\n", inventory[]);

/*
The code above outputs the following:

You have:
["sword", "shield", "healing potion"]
*/

Those were one dimensional arrays. Now, I present to you multidimensional arrays...

What the h*** are multidimensional arrays?

D supports arrays in multiple dimensions.

Here, I will be discussing two dimensional arrays.

Two dimensional arrays are basically arrays with one-dimensional arrays

Think of a table (document kind not lua-version-of-array kind.)

Notice how tables have rows and columns?

Well that's basically what a two dimensional array is.

Look at the following table:

----------------
| 27 | 48 | 21 |
----------------
| 76 | 32 | 12 |
----------------

Well, let's organize that into a two dimensional array.

The syntax for a two dimensional array:

int twodee[<rows>][<columns>] = [
	[/*add a value for each column in each row.*/]// Don't forget a comma at the end of a row that's not the last row.
	//do this for each row
]; //don't forget the semicolon

Anyways, let's look at what a two dimensional array version of that table would look like:

int table[2][3] = [
	[27, 48, 21],
	[76, 32, 12]
];

This is pretty handy for a 2D platformer game.

Slices

One of the most pleasant features of the D language is its implementation of slices. Every time I use a programming language that isn't D, I find myself lamenting for D's slice syntax. Not only is it concise and efficient, but things 'just work' when you are dealing with slices.

Steven Schveighoffer, D Slices

This is a really good feature of D, slices.

Slices are little parts of an array stored in a new array.

They have the following syntax:

<data type>[] <slice_name> = [<first_value_in_new_array>..<first_value_NOT_in_new_array>];

Here is an example with the with a slice from the inventory example:

string[] part_of_inventory = inventory[1..3];
writeln(part);

Operators

The operators you would need are as following :

================================
           ARITHMETIC
================================
  + | Addition
  - | Subtraction
  * | Multiplication
  / | Division
  % | Division but returns the remainder of integral quotient
 ++ | Increment
 -- | Decrement
NOTE: Put an increment/decrement before the variable to increase the value before the result is assigned.
================================
     ARITHMETIC ASSIGNMENT
================================
 += | Adds something to a certain value, then saves the result to variable
 -= | Subtracts something from a certain value, then saves the result to a variable
 *= | Multiplies something by a certain value, then saves the result to a variable
 /= | Divides something by a certain value, then saves the result to a variable
 %= | Divides something by a certain value, then saves the remainder to a variable
================================
           COMPARING
================================
 == | Equal to
 != | Not equal to
  > | greater than
 >= | greater than or equal to
  < | less than
 <= | less than or equal to
 is | has identity
!is | doesn’t have identity
NOTE: is and !is can be used to check whether a variable is null
================================
         BOOLEAN LOGIC
================================
 && | boolean AND
 || | boolean OR
  ! | boolean NOT. 

Control flow

For now, our programs execute every line of code. That is impractical (unless you're recreating scratch animations in D.) So let's give our programs some conditional statements and loops.

if, else if, and else - The most basic conditionals

if, else if, and else are basic, but a fundamental part of programming. They can be seen in almost all programs, so you have to learn them.

WARNING: You need to import strip from std.string to be able to compare strings from `readln.

if statements start a block of code that only executes if the condition is true.

Example:

if (<condition evaluated>) {

}

When you need to have multiple conditionals, you use else if

Here is an example:

import std.stdio: writeln, write, readln;
import std.string: strip;

void main() {
	writeln("Is quarantine boring? (y/n)");
	string answer = strip(readln());
	if (answer == "y" || answer == "Y") {
		writeln("Yep, you're right.");
	}
	else if (answer == "n" || answer == "N") {
		writeln("Well, good for you. Hope you have fun stuff to do while the rest of us be bored!");
	}
	else {
		writeln("I don't understand that.");
	}
}

/*
Sample output:

Is quarantine boring? (y/n)
y
Yep, you're right
*/

Switch statements, short conditions for one variable

Sometimes, regular conditionals can be impractical if:
1. they're based on the same variable.
2. there's a ton of them.
Introducing...

...switch statements!

Switch statements have cases, or stuff to execute if the statement is true.

They also need a default case if none of the other cases are executed.

Every case ends with break to stop it.

Here is the basic syntax:

switch (<variable>) {
	case case1:
		// add code here
		break;
	case case2:
		// add code here
		break;
	default:
		// add code here
		break;
}

There's also goto, which can be used to go to different cases.

There are three basic uses of goto in switch statements:

  • goto case - Goes to the next case
  • goto case (case_value) - Goes to the case with that value
  • goto default - Goes to the default case

    NOTE: You do not need to include a break; if you have a goto.
    gotos are also considered bad practice among most programmers, but sometimes they are an easy way to solve a problem. But be careful:

So now that you understand the syntax, let's look at a switch statement version of the above example:

import std.stdio: writeln, write, readln;
import std.string: strip;

void main() {
	writeln("Is quarantine boring? (y/n)");
	string answer = strip(readln());
	switch (answer) {
		case "y":
			writeln("Yep, you're right.");
			break;
		case "Y":
			goto case "y";
		case "n":
			writeln("Well, good for you. Hope you have fun stuff to do while the rest of us be bored!");
			break;
		case "N":
			goto case "n";
		default:
			writeln("I don't understand that.");
	}
}

Loops

Wanna repeat a bunch of code without having to copy and paste a ton?

Then use loops. They repeat code until a condition is false.

Loop keywords

There are two main loop keywords, continue and break
continue will immedietely continue to the next iteration of the loop

break will stop the loop

while loops

while loops check if the condition is true. If it's true, then it executes the code inside the braces.

Example:

int counter = 0;

while (true) {
	writeln(counter);
	counter++;
	if (counter >= 1000) {
		break;
	}
}

// This loop will iterate about 1000 times, printing numbers 0-999. When it is equal to or greater than 1000, the loop stops

do-while loop

When using a regular while loop, it's possible the loop will never iterate.

So you have the do-while loop that checks the condition when the iteration is done.

Example:

int counter = 0;

do {
	writeln(counter);
	counter++;
	if (counter >= 1000) {
		break;
	}
} while (true); // Don't forget the semicolon!

for loop

A for loop is complex but really useful.

It's a more concise version of the while loop.

The for loop consists of three expressions:

  • Expression 1: Thing to do before loop starts iterating
  • Expression 2: Condition to check when each iteration is complete
  • Expression 3: What to do when loop completes

Basic syntax:

for (<expr1>, <expr2>, <expr3>) {

}

Now here's a more concise version of the while loop example:

for (int counter = 0; counter < 1000; counter++) {
	writeln(i);
}

foreach and foreach_reverse

We're moving on to the last types of loops, foreach and foreach_reverse.

foreach is a loop that will iterate for each thing in something.

That thing is usually one element in an array.

That something is usually an array.

Here's an example of one with an array.

string webdevlangs[] = ["HTML", "CSS", "JavaScript", "WebAssembly (WASM)"];

foreach(string lang; webdevlangs) {
	writeln("- ", lang);
}

/*
Output:

- HTML
- CSS
- JavaScript
- WebAssembly (WASM)
*/

You can also have range based foreach loops

The ranges follow the following pattern:

<first_number_in_range> .. <first_number_NOT_in_range>

Same pattern for slices.

foreach_reverse is basically the same, except it iterates in reverse order.

An example of foreach_reverse:

foreach_reverse(int num; 1 .. 11) {
	writeln(num, "!");
}
writeln("BLASTOFF!!!!!");

Labels

Labels are cool and concise.

They are basically making a variable for a loop.

But the syntax is different.

Example:

label_name: while (true) {
        // code
}

The thing that makes it really useful is the fact that you can continue or break a label for a loop.

Syntax:

continue <loop_label>;
break <loop_label>;

Functions

Functions are an essential part of programming.

writeln is a function. readln is a function, you name it. Everything that can be called with two parenthesis is a function.

But sometimes you need to define your own.

Actually, we already defined our own before. main is a function.

It's just a special function because that's the program's entry point.

We will start looking at the basics of function, then about defining your own.

What are functions

Functions are snippets of code that can be called with parenthesis.

Functions have parameters, or local variables inside the function.

When parameter values are assigned when the function is called, those values are called arguments.

You don't have to assign it a value, the value will be assigned in the arguments.

But if you do, the parameter will have a default value if it is not given an argument.

Functions can also return values, allowing them to be used for variables.

You use the return keyword to return a value.

Example:

return <value>;

Of course, you replace value with the value or variable.


Defining your own Functions

Before you put the function name and the parameters, you put the return type. This can be anything.

If the function will not return anything, then put void.

Then there's the name. Follow the same rules as if you are naming a variable.

Here is an example of a non-return function:

void printSquaredNumber(int number) {
	int squared_number = number * number;
        writeln(squared_number);
}

That function will not return anything, but it will print the a squared number to the console.

Now for a function that will return something:

string prompt(string prompt_text = " >> ") {
	write(prompt_text);
	string input = readln();
	return input;
}

You can do that same thing with readln and write, but it's better to make it into a function, especially if yo are gonna have a lot of console input.


Exception Handling Basics

Exceptions are basically errors that happen while the program is running.

They can happen for all sorts of reasons. Let's say, for example, that you want to make a program that will take a number the user typed in and convert it to a double to get the cube root of it.

The program might throw an exception if the user typed in something that can't be converted to a double.

That would stop the program. We don't want that.

A basic and effective way to do this is a chain of try-catch-finally blocks.

Each blocks' behavior is explained in the example below:

try {
        // Code that may have the danger of throwing an exception
)
catch (exceptionName e) {
        // Code that runs if that exception is thrown
}
catch (otherExceptionName e) {
        /*
        Code to be run if other exception is thrown.
        And yes. You can have as many catch blocks as you need.
        */
}
finally {
        // This block of code is runs after the try-catch blocks are run regardless if it threw an exception or not.
}
// You can also have "catch {}" to  catch any exception.

The basic idea is that the program tries to run the code in the try block.

If it throws an exception, then the code runs the matching catch block for the exception.

Afterwords, the program runs the finally block. It doesn't matter whether the program threw any exceptions or not.

Then the program keeps running (if there were no unhandled exceptions.)


Structs

Thanks to @CodeLongAndPros for suggesting this topic.

structs are one way you define your own data types.

They are usually made my combining a bunch of types.

Example:

// declaring the type

struct pokedex_entry {
        int level;
        int exp;
        string name;
        string pokemon_type;
}

// using the type

pokedex_entry Pikachu = pokedex_entry(23, 945, "Pikachu", "Electric");

Like in functions, you can assign default values for each combined type.

Example before but with default values:

struct pokedex_entry {
        int level = 47;
        int exp 55684;
        string name = "Cinderace";
        string pokemon_type = "Fire";// it's from pokemon sword and shield btw
}

To access a certain member of a function, you put the variable, a dot, and then the name of the variable member you would like to change.

// LEVEL UP!
++Pikachu.level;

TODO: explain this keyword in structs


Imports

Thanks to @CodeLongAndPros for suggesting this section.

The standard D runtime library is Phobos.

It has a bunch of things you can use in imports.

The imports starting with std are usually regular modules.

The ones starting with ect are usually from C or C++.

And finally, the ones starting with core are usually low level.

There are many things in Phobos. Here, we will cover important parts and some of their important functions.

So now I will start talking about the important things.


std.stdio

I hope you know what this does by now, but there are more things I can discuss that I have not mentioned.

Other useful things:

  • file - A struct for file manipulation
  • writef and writefln - They are basically D's ways to do C's printf

std.math

This provides functions and constants for dealing with more complicated math than basic operations.

Important functions

  • sqrt - Get square root of number.
  • cbrt - Get cube root of number.
  • abs - Get absolute value of number.
  • floor - Round down to the nearest integer.
  • ceil - Round up to the nearest integer.

std.random

Provides functions for generating random numbers.

Important functions:

  • uniform - Generates a random number between two numbers. It auto-guesses the type, so if it's two integers, it generates two integers.
  • dice - Generates a number low number (like 0, 1, or 2) with specific probability. It can take at least two arguments. Two arguments mean either 0 or 1.
  • choice - Returns a random element from a range.

std.array

Array manipulation.

Important functions:

  • join - Join elements of an array. Takes an optional second parameter to put after each element of array.
  • replace - Replace all occurrences of a specified subrange with a new thing
  • replaceFirst - Replace the first occurrence of a specified subrange with a new thing.
  • replaceLast - Replace the last occurrence of a specified subrange with a new thing.

There are too many things in Phobos to mention in this tutorial. You can see all that Phobos has to offer here.


Classes

Now, we'll deal with classes.

Since D has support for OOP, you can use classes.

Example:

class sample {
	...

But there's more to classes than that.

For another class to inherit from one another you put a colon then the class name.

You cannot inherit multiple classes.

Consider this example from the Dlang Tour:

class Foo { } // inherits from Object
class Bar : Foo { } // Bar is a Foo too

Sometimes you need a reference for a class to use stuff from it. As usual, there is a way to do that.

They are called references.

Consider this example from the Dlang Tour.

Bar bar = foo; // bar points to foo

More about Unicode in D

D has full support for Unicode.

Unicode is an encoding scheme.

To understand what that is, we need to understand how a computer works.

At a basic level, computers use numbers to perform operations. So they need a way to turn that into basic text.

That's where encoding schemes come in. They turn those numbers into text.

Unicode is an example of an encoding scheme. It's also a global standard.

C/C++ strings and characters are just bytes essentially. But D strings and characters are Unicode characters

D supports UTF-8, UTF-16, and UTF-32 characters with different types of characters and strings.

-----------------------------------------------
| Char type | String type | UTF character set |
-----------------------------------------------
|   char    |   string    |      UTF-8        |
-----------------------------------------------
|   wchar   |   wstring   |      UTF-16       |
-----------------------------------------------
|   dchar   |   dstring   |      UTF-32       |
-----------------------------------------------

Conclusion

D is a great language. You can make lots of things with it.

It runs really fast, so it's good for video games and all sorts of stuff.

It's made to feel like C and C++, so it's easy to use if you come from one of those languages.

It's multi paradigm, so your D programs can be Object Oriented, imperative, structured, ect.

It has full support for Unicode, so you have a big character set to use.

So go to wherever you can code in Dlang, and have fun


Sources

Comments
hotnewtop
JustAWalrus (1192)

We all needed another C-Family Copycat didn't we?

xxpertHacker (931)
string inventory[] = ["sword", "shield", "healing potion"];
writeln("You have:\n", inventory[]);

Odd, I always wrote it like this instead:

string[] inventory = ["sword", "shield", "healing potion"];
writeln("You have:\n", inventory);

Know if it's any different?

xxpertHacker (931)

lmao, nice! You might want to mention that D is slower than C / C++, and that it's a garbage collected language, like Java.

DungeonMaster00 (189)

will probably make an intermediate and advanced course now

DungeonMaster00 (189)

apperantly the repl.it team will add D to the official list of languages if https://repl.it/language-requests/p/d gets enough upvotes.

Jakman (452)

Talk about memory allocation in D

DungeonMaster00 (189)

think i fixed most of the major typos

CodeLongAndPros (1631)

This is great!
Perhaps a little more on classes, and struts, imports, and the this operator?

DungeonMaster00 (189)

@nk1rwc probably done by end of august tops

DungeonMaster00 (189)

@nk1rwc (silently) raging against the machine when a bunch of revisions were lost even though i remember updating the post (pun intended)

xxpertHacker (931)

@CodeLongAndPros That ought to be the next tutorial in the series. lmao

xxpertHacker (931)

@nk1rwc Oh shoot, sorry, I helped setup the Bash, but later improved efficiency and control flow, it seems like the post wasn't updated to reflect that, go use the Repl I setup seperately from CodeLong at: https://repl.it/@StudentFires/Dlang-template.

DungeonMaster00 (189)

@StudentFires its fine i improved this again

xxpertHacker (931)

@nk1rwc Improved what? The Bash seem the same.