Monthly Archives: August 2015

Dynamic arrays, strings

Dynamic arrays consist of a length and a pointer to the array data. Multiple dynamic arrays can share all or parts of the array data.

A dynamic array can be thought as:

where T is the type of data the array holds.

  • Dynamic arrays are allocated on the garbage collected heap (unlike static arrays which live on the stack)
  • Like static arrays, they have a .length property, which is the number of elements in the array
  • Like static arrays, dynamic arrays can be returned from functions
  • Unlike static arrays, they can be resized at runtime
  • Dynamic arrays can be sliced

How to define a dynamic array

Dynamic arrays can be concatenated

Dynamic arrays can be concatenated using the concatenation operator, ~.

Dynamic arrays can be resized

By changing the length property, you can resize a dynamic array. If a smaller value than the current one is set, the array is shrunk.

In the example above, we read a number from the user and allocate a dynamic array of that size. Then we read another number and resize the array to the new size.

Dynamic arrays can be sliced

Array slicing is an awesome feature of D arrays. By slicing an array, you get a different view of the original array, without any memory allocations involved.

In the program above, we have function isPalindrome which returns true if a string is palindrome, otherwise false. The function is recursive, that is, it calls itself with a different argument each time, until it reaches a state in which it terminates.

The first thing we do in isPalindrome is to check whether the string is the empty string, or has length 1. By definition both of these are palindrome.

Then we compare the first character of the string with the last one. If they are not equal, the string is not palindrome, so we return false. In D, you can use the $ character inside array indixes, which denotes the length. This is a shorthand for str[str.length – 1].

Finally, the function calls itself with a slice of the string, using the slice operator, ... The slice contains all characters except the first and the last.

To better illustrate what happens, consider a call to isPalindrome with the argument “abccba”.

Recursion depth string isPalindrome?
0 “abccba” true
1 “bccb” true
2 “cc” true
3 “” true

So after 4 tests, the algorithm decides that “abccba” is indeed a palindrome string.

You might have noticed the @nogc annotation on the function. This ensures that no GC allocations can occur.

Yes, strings are dynamic arrays!

In the previous example, I have used a string, while we are talking for dynamic arrays.
In fact, a string is a dynamic array of immutable characters!

A string an alias for immutable(char)[].
That’s all you need to know about strings for now. We will talk about immutable data in a later tutorial.

Things to remember

  • Dynamic arrays are allocated on the garbage collector’s heap
  • DAs can be concatenated using the ~ operator
  • DAs can be resized by changing their length property
  • DAs can be sliced using the .. operator
  • array[$ – 1] is a shorthand for array[array.length – 1]
  • The string type in D is nothing more than an alias to immutable(char)[]. Thus, strings are dynamic arrays as well

Static arrays

  • Static arrays are analogous to C arrays. They are distinguished by having a length fixed at compile time.
  • The total size of a static array cannot exceed 16Mb. A dynamic array should be used instead for such large arrays.
  • A static array with a dimension of 0 is allowed, but no space is allocated for it. It’s useful as the last member of a variable length struct, or as the degenerate case of a template expansion.
  • Static arrays are value types. Unlike in C, static arrays are passed to functions by value. Static arrays can also be returned by functions.

How to define a static array

Non matching sizes result in a compile error.

Static arrays are value types

Because static arrays are value types, when copying one into another, the elements are copied as well. In the example above, we see that the mutation in t0 did not affect t1.
As we will see in the next tutorial, this is not the case with dynamic arrays.

Static arrays know their length

Static arrays (and dynamic) have a .length property. Its type is size_t and returns the number of elements in the array. Note that for static arrays, this is the size the array was initialized with and cannot change.

Calling functions that accept a pointer

Sometimes you might have a function that takes an array as a pointer as its argument, e.g when calling a function from a C library.
Static arrays have a .ptr property that is a pointer type.

Further reading

See the reference on dlang.org.

Basic Data Types

D provides a set of data types, called primitives (built-in).

Type Default value Memory consumption (bytes) Description
bool false 1 true or false values
byte 0 1 Signed integer [-128, 127]
ubyte 0 1 Unsigned integer [0, 255]
short 0 2 Signed integer [-32768, 32767]
ushort 0 2 Unsigned integer [0, 65535]
int 0 4 Signed integer [-231, 231 – 1]
uint 0 4 Unsigned integer [0, 232 – 1]
long 0 8 Signed integer [-263, 263 – 1]
ulong 0 8 Unsigned integer [0, 264 – 1]
float float.nan 4 Single precision floating point number
double double.nan 8 Double precision floating point number
real real.nan ≥ 8 The largest floating point type available in the current CPU
char 0xFF 1 UTF-8 code unit
wchar 0xFFFF 2 UTF-16 code unit
dchar 0x0000FFFF 4 UTF-32 code unit and code point

Default values

Data types in D have default values (listed in the table above).

Tip: To quickly test the above program, copy the code into a file, save it and execute

rdmd FILENAME

Avoiding default values

It is possible avoid default initialization of variables, by assigning them the type void.

You can use it for when you can convince yourself that you write into a variable and then use it (read its value).

Type properties

Types in D have various properties defined on them:

Property Description
.stringof Name of the type
.sizeof Size of the type in bytes
.min Minumum value the type can have
.max Maximum value the type can have
.init Default value of the type

size_t

Just like C++, D also have the size_t type. size_t is an alias for uint on 32-bit machines and ulong on 64-bit machines.

Things to remember

  • Unlike C++, D’s primitive data type sizes do not depend on the platform. An int will always be 4 bytes
  • Primitives have properties that you can use when you need to
  • Primitives are initialized by default to specific values
  • You can skip default initialization by assigning void to a variable

Hello, World!

Finally, it’s time to start writing some code! So let’s get started!

First, open a terminal and type

dub init hello_world

This will create the following directory tree:

app.d is a source file generated by dub. Open it with a text editor, e.g Notepad.

Inside you will see:

Modify it to look like:

Alright, now let’s run it! In your terminal, execute

dub run

If you haven’t made any mistakes, you will see

Building hello_world ~master configuration “application”, build type debug.
Compiling using dmd…
Linking…
Running ./hello_world
Hello, World!

The last line, “Hello, World!” is the output of the program.

Installing dub

dub is a package and build manager for D applications and libraries.

Installing on Debian/Ubuntu

Open a terminal and execute the following commands:

sudo wget http://netcologne.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list

sudo apt-get update && sudo apt-get -y --allow-unauthenticated install --reinstall d-apt-keyring && sudo apt-get update

sudo apt-get install dub

Installing on Windows

Head over to http://code.dlang.org and select DUB x.y.z installer for Windows (X86). After the installer is downloaded, execute it to install dub.

Installing on OSx / other

Follow the instructions here. I don’t have a MAC so I was not able to verify it.

 

Verifying the installation

To verify that you have installed dub correctly, open a terminal and type

dub

If the output is something like:

we are good to go!