Review of the D 2 Programming Language
Familiarity with C is assumed.
First Program
import std.stdio;
int main() {
writefln("Hello world");
return 0;
}
High-Level Feature List
- Garbage Collection exists and is used.
- Manual freeing of allocated memory is possible.
- Lambdas exist and are used.
- Automatic type inference exists and is used. Limitation: the First Program above would not work with auto main
- typeof exists and can be used in variable and parameter declarations, also typeof(return)(...) works.
- Lazy evaluation exists and can be optionally specified by a type modifier of a parameter.
- Closures exist and work properly.
- Exceptions exist and are used.
- Classes exist and are used. Topmost class is Object.
- All variables are automatically initialized.
- Has Module System.
- Templates that don't suck exist. One-similarly-named-member will replace template instantiation if needed.
- Uniform Function Call Syntax is used (as in Go, Dylan). So v.foo(arg) is the same as foo(v, arg) .
- Proper arrays with length and fallback to the element pointer (using ptr) exist.
- Ranges as safe-ish arrays and interfaces to array-like things and iterators exist.
- Implicit casts are done a lot less than in C.
- Strings are built-in and immutable.
- Associative arrays (dictionaries) are a built-in type.
- Types can have modifiers like immutable, const, shared.
- Functions can be pure or nogc.
- Variable arguments are handled a lot nicer than in C.
- Operator overloading exists.
- Array and associative array literals (with []) and struct literals (with {}) are possible.
- foreach exists (foreach(char[] arg; args) ...).
- version blocks which allow conditional compilation of blocks exist.
- Array Slices as views into "larger" arrays exist.
- Supports function contracts (preconditions, postconditions, invariants) like void foo() in { assert ... } out(result) { assert ...} body {...} invariant { ... } .
- Built-in functionality for unit tests exists, also doctests exist.
- scope exists. It is used for deferred cleanup (scope(exit) { ... }). Also for marking that parameters are not used beyond the scope of the function.
- scoped exists. It is used to force stack allocation. Is unsafe.
- @disable to disable constructors exists.
- Float literals: 1.23 or 0x9a.bc or 0xabc.defP4 or 1_000.5. The f modifier is for using float.
- String literals: escaped-aware "xxx", raw `xxx` or multiline q"EOF...EOF".
- goto case in switch must be used to go to the next case.
- Volatile accesses (__iomem) are done using special functions (volatileLoad, volatileStore).
- std.algorithm: map and filter exist.
- opDispatch member function: called when a message arrives that the object does not understand.
- C interop: strdup exists and returns a char[].
- std.array.appender exists: used for repeated appending to something (i.e. strings etc), also formattedWrite. Read result using data
High-Level "Cultural" Problems
- C-like model for numbers: no overflow detection, division of integers truncates.
- Java-like model for exceptions: you cannot resume where an exception was caused (to retry). Exceptions are class instances.
- For all reference types: null is a member. (though see Nullable)
- Even though Algebraic exists, unions still exist and the compiler still can't decide between the fields on its own.
- Algebraic cannot be recursive.
- Lexical Order at global scope doesn't matter. Why not?
- Mutable is the default.
- Impure is the default.
- Operator overloading doesn't work with a global function as implementation.
- Type declarations are read right-to-left, as in C. double[int][string] is an associated array from a string to (an associated array from an int to a double)
- Primitive Types like int etc have a fixed size regardless of architecture - rather than what's the biggest fits-into-register integer or float.
- Even though closures work, the closures are called "delegates" and the C-like functions without any context are called "functions" even though in the field there are only functions. There's a delegate keyword and a function keyword and they differ.
- enum is used for int and string constants (among other things), and algebraic data types are not called enum. Also, C enum "values" are automatically "converted" to integers.
- Uses opCmp as shortcut for defining all the ordering relation, even though it's possible for a number to be neither smaller NOR bigger than another number. Not sure if opCmp can be replaced by opEquals then.
- Calls a type real that is not the real numbers.
Implementation Problems
- Bindings for many Linux headers are missing.
- No clear road for streams and main interface is deprecated.
- gdc needs strange command line arguments (-frelease -O3 -fdata-sections -Xlinker --gc-sections and then strip) in order to make it do smart linking and get a reasonable executable file size.
Tips
Block commenting is possible using version (none) { ... } .
Types
Character
- char: UTF-8 code unit.
- wchar: UTF-16 code unit.
- dchar: UTF-32 code unit and Unicode code point, max 0x0000FFFF anyway (WTF).
wchar currencySymbol = '\€';
wchar Ğ_w = '\u011e';
dchar Ğ_d = '\U0000011e';
Void
Integers
- int
- uint
- byte
- ubyte
- long
- ulong
Floating-Point
String
Others
- function "pointer"s
- arrays
- associative arrays
- enums
- Algebraic
- structs
- unions
- classes
- variant
System Library Bindings
- Gtk+, gstreamer, gda, gl, sv, vte bindings exists. (GtkD)