A Beginner's Guide to D/The Basics/Types and Math
What are types?
If you look directly at the contents of a computer's memory, you see only a lot of bytes. These are often shown as numbers but in fact they don't have a meaning on its own, not even the meaning of a number.
Types are used in computer languages like D or C to give one byte or a sequence of bytes a meaning. Types define if these bytes are a number, a text, a date or whatever.
The Basic Types
Two basic types have already been introduced: int and float, for non-decimal and decimal numbers, respectively. Here, all of the basic types are introduced, including limits on their values and how large they are in memory.
|Type||What it Is||Lower Limit||Upper Limit||Storage Size|
|byte||A very small, integer number.||-128||127||8 bits (1 byte)|
|ubyte||A very small, integer, non-negative number.||0||255||8 bits (1 byte)|
|short||A small, integer number.||-32768||32767||16 bits (2 bytes)|
|ushort||A small, integer, non-negative number.||0||65535||16 bits (2 bytes)|
|int||A integer number.||-2147483648||2147483647||32 bits (4 bytes)|
|uint||A integer, non-negative number.||0||4294967296||32 bits (4 bytes)|
|long||A potentially huge, integer number.||-9223372036854775808||9223372036854775807||64 bits (8 bytes)|
|ulong||A potentially huge, integer, non-negative number.||0||18446744073709551616||64 bits (8 bytes)|
|float||A number.||About -3.4e38||About 3.4e38||32 bits (4 bytes)|
|ifloat||An imaginary number.||About -3.4e38i||About 3.4e38i||32 bits (4 bytes)|
|double||A potentially huge number.||About -1.8e308||About 1.8e308||64 bits (8 bytes)|
|idouble||A potentially huge number imaginary number.||About -1.8e308i||About 1.8e308i||64 bits (8 bytes)|
|real||A potentially gigantic number. The maximum size of decimal number that the computer is capable of supporting on the processor. Only generally defined as larger than double on x86 processors.||(On x86) About -5.9e4436||(On x86) About 5.9e4436||(On x86) 80 bits (10 bytes)|
|ireal||A potentially gigantic imaginary number.||(On x86) About -5.9e4436||(On x86) About 5.9e4436||(On x86) 80 bits (10 bytes)|
|char||A single element of text. Usually used for displayable, printable text, but can technically be used for anything that will fit. 'a', '0', '.', '+', ' ' are all valid chars. There are several ways to encode a character to a char, this type uses the UTF-8 encoding that encodes the most used characters with a smaller size.||0||255||8 bits (1 byte)|
|wchar||A single element of text encoded as UTF-16. If you are not sure what this means use 'char'.||0||65535||16 bits (2 byte)|
|dchar||A single element of text encoded as UTF-32. If you are not sure what this means use 'char'.||0 (not a displayable text element)||4294967296||32 bits (4 byte)|
The types which cannot be decimal take less time (are more efficient) for math. The numbers which can be decimal are unpredictably less accurate for larger numbers. chars can, in general, be used exactly like ubytes, but their purpose is different.
[TODO: Should some of the following sub-sections be placed elsewhere?] You can initialize a basic variable, or set it to a default value, by assigning it a value in its declaration:
int five = 5; double twoPointFive = 2.5;
In D all basic variables have a default value that they are initialized to if the programmer does not specify one. This may seem intuitive, but some languages (most notably C) do not automatically intialize variables unless explicitly told to do so which can lead to many problems because without intialization variables contain garbage by default (as an artifact of how computer memory works). All integer number types are default initialized to 0. All decimal number types are default intialized to NaN, a special value meaning "Not a Number". Character types are default initialized to their maximum values. If you specifically want any basic variable to be initialized with garbage, initialize them with the special value void which means no initialization.
int garbage = void; //This variable contains garbage
Note: Do not count on the garbage in a void-intialized variable being random; more often than not it will be anything but.
Imaginary and Complex Numbers
If you are not familiar with the mathmatical concept of imaginary and complex numbers, feel free to skip this sub-section. D has built-in support for imaginary and complex decimal number types. D's imaginary and complex number types are based on its real decimal types (float, double, or real). An arithmatic operation involving a real decimal number and an imaginary or complex number results in a complex number and all complex arithmatic works the same as in algebra. The type names of imaginary number types are the same as real decimal types except they are prefixed with an i, and the type names of complex numbers are likewise the same as real decimal types except prefixed with a c. Imaginary numbers are initialized to NaN * 1.0i, and complex numbers are initialized to NaN + NaN * 1.0i. Imaginary literals are the same as decimal literals except they are followed by an i. Complex literals are simply real literals plus imaginary literals. For example:
double realDouble = 5.0; idouble imaginaryDouble = 5.0i; cdouble complexDouble = 5.0 + 5.0i; cdouble exampleOperation = complexDouble + 5.0i; // exampleOperation now equals 5+10i
One footnote is that complex decimal types take up double the amount of memory as their base real and imaginary decimal types because complex types are really just a real decimal and an imaginary decimal number stored together as one variable.
User Defined Types
D also supports several user defined types including enums, structs, classes, and more. These types are very powerful, but they are much more complicated to use. They will be covered in-depth later in the book.
An array is a way to group data of the same type. An array contains any number of elements, and each element is a value of a specified type.
Arrays can be made from any type (including other array types) similarly. The type for an array of ints with 5 elements is:
So, a variable called 'a' which is an array of 5 ints is:
Of course, this can be generalized for any type and count:
You can also create arrays with no specified number of elements, which can then be expanded to fit any number of elements. These are called dynamic arrays, and the alternatives (with a set number of elements) are called static arrays. They are specified similarly to static arrays, but the count is excluded. A dynamic array of any number of ints is:
A variable called 'a' which is a dynamic array of any number of ints is:
And of course, this can be generalized for any type with:
[TODO: Array literals and initializing dynamic arrays to them? Should this be saved for later?]
Array elements can be accessed like normal variables in code. That is, you can use an array element nearly anywhere you could use a simple value. To access element 1 from an array named 'a', for example:
The number for the element is called the index. The range of valid indexes is from 0 to 1 less than the number of elements; that is, for an array with 5 elements, the range of valid indexes is from 0 to 4, not from 1 to 5.
Array access can of course be generalized:
And the index can be far more complex than just a number: it can be a variable, or even a mathematical expression.
In D and many other language, a series of textual characters is called a string. In some languages, there is a special type dedicated to this, but D takes it at face value: a string is just a series of characters, and a series of characters is just an array of characters. So, you can use the char type (that is, a dynamic array of chars) as a string.
Similar to numeric types where you could either write a variable of numeric type or directly a fixed number in an arithmetic expression in the source code and where you could assign a fixed number to a numeric variable, you can write a fixed string in the source and assign it to a char variable (often also called string variable).
To mark something as a fixed string (a so-called string literal) it must be enclosed in double quotation marks:
A program writing this string literal to a console window (also known as a DOS-box in Windows), such as the example given in Basic Output, would give:
Notice the lack of quotes in the output.
Sometimes you want to add "special" characters to a string literal. This means
- characters not available on your keyboard
- control characters which are not visible when printed but instead are a simple command to the console to do something.
- characters with particular meaning like the double quotation mark.
The most commonly used of the second category is the newline character which ends one line on a console
and starts a new one.
To include such characters in a string literal, you use escape sequences. An escape sequence starts with a backslash "\" in the literal followed by one or more characters describing the desired character. For a newline character simply add "n" after the backslash.
If you were to replace the above "Hello, world!" literal with this one, the program would write
on the console.
Other useful escape sequences are \" which adds a double quotation mark (without the backslash, the quotation mark would terminate the string literal) and \\ to add one backslash to the literal.
"\"Interesting, \\\nor not?\", he said"
"Interesting, \ or not?", he said
Sometimes you need to just grab part of a string. To do this use Array slice notation, which is the two '.'s between the indices you want to get the substring of lower bound inclusive and upper bound exclusive. Say we just wanted "Interesting" from the string seen above, we would do the following.
"\"Interesting, \\\nor not?\", he said" [ 1 .. 12 ]
[TODO: non-ascii characters like umlauts. How to output them on Windows? Create some "magic" function?]