Overview | Comparisons | Discuss |
Examples | GTK | Injection |
Install | Library | Logging |
Nulls | Plans | Syntax |
Types |
Delight inherits most of its type system from D. This page contains a brief summary, and a list of the changes from D.
The basic types are the same as in D. The main ones are:
# Integers, signed and unsigned
bool
byte, ubyte
short, ushort
int, uint
long, ulong
# Floating point values with various levels of precision
float, double, real
# Complex values
cfloat, cdouble, creal
# UTF 8/16/32 elements
char, wchar, dchar
There are three types of array:
# A static array
# (four integers, initially all zero)
int[4] a
a[0] = 50
# A dynamic array
# (initially empty)
int[] b
b ~= [1,2,3] # Append three values
# An associative array (hash / dictionary / map)
# (initially empty)
int[int] c
c[400] = 123
Array accesses are bounds-checked.
An important difference between D and Delight is that a Delight array is considered true if and only if its length is non-zero:
int[] a
assert not a # Empty
a = []
assert not a # Still empty
a = [0]
assert a # Contains a 0
In D, an empty array may be considered true or false, depending on exactly how it was allocated. Also, D allows null to be used to mean an empty array. In Delight, you can only use [].
Delight inherits D's powerful (but somewhat complicated) const/invariant system. Some examples:
# This function requires an array it can change
void a(char[] data): ...
# This function will not change the array
void b(const(char)[] data): ...
# This function requires an array that will not change
void c(invariant(char)[] data): ...
Neither b not c can change their input array, but c additionally requires that no-one else will change it either. For example, c might want to store the data somewhere and use it later.
These modifiers are transitive: if foo is const then so are foo.a and foo.a.b, etc.
Mutable and invariant types are implicitly converted to const where needed.
If an object is const, only const methods on it can be called. A const method looks like this (days):
class Foo:
int weeks = 2
int days() const:
return weeks * 7
unittest:
const f = new Foo()
assert f.days == 14
This has the effect of making the implicit this parameter const in the method.
The string type is defined as an alias for an array of invariant characters:
alias invariant(char)[] string
Therefore, strings never change. If you want to edit a string, use dup to make a mutable copy. Use idup to get an invariant copy:
string spaceToUnder(string before):
char[] buffer = before.dup
for ref char c in buffer:
if c == ' ': c = '_'
return buffer.idup
assert spaceToUnder("a nice message") == "a_nice_message"
(note the use of ref to make c refer to the element in the buffer, rather than a copy of it)
Structs work just as in C. They are allocated on the stack and passed by value (copied).
Classes are implemented as pointers. They are allocated on the heap and passed by reference.
class Foo:
char[100] name
struct Bar:
char[100] name
void myFunc():
Foo foo = new Foo()
Bar bar
Class pointers cannot be null by default. See the NullPointerException page for details.
You can also use pointers (as in C), but usually you won't need them. Arrays are bounds-checked, but there are no safe-guards when using pointers.
If you want a variable to hold a call-back, use:
int myFunc(string a):
...
int delegate(string a) myCallback
myCallback = &myFunc
myCallback("foo")
A delegate is a structure containing two pointers: the address of the function and a context. A delegate can therefore be used to hold a method on a particular object. There is also a simpler function type which only holds one address. You should probably avoid using this as it's less flexible.
# A named enum
# (creates a new type extending int)
enum Colour: Red, Green, Blue
assert Colour.Red == 0
assert Colour.Green == 1
Colour c = Colour.Blue
# An anonymous enum
enum extends bool: On = true, Off = false
assert On == true
# The values can be specified explicitly
enum Flags:
None = 0
Needed = 0x1
Provided = 0x2
Error = 0x4
Casting a class to another class results in null if the object isn't derived from the target class or interface. The result is therefore a maybe type, which you can remove using an if statement, e.g.
void age(Tree tree):
if Oak oak = cast(Oak) tree:
oak.produceAcorns()
Of course, casting should be avoided where possible. A generic produceSeed method would have been more appropriate in this case.
Install it and try it out...
Overview | Comparisons | Discuss |
Examples | GTK | Injection |
Install | Library | Logging |
Nulls | Plans | Syntax |
Types |