D is statically typed. Every expression has a type. Types constrain the values an expression can hold, and determine the semantics of operations on those values.
Type:TypeCtorsoptBasicTypeTypeSuffixesoptTypeCtors:TypeCtorTypeCtorTypeCtorsTypeCtor:constimmutableinoutsharedBasicType:FundamentalType.QualifiedIdentifierQualifiedIdentifierTypeofTypeof.QualifiedIdentifierTypeCtor(Type)VectorTraitsExpressionMixinTypeVector:__vector(VectorBaseType)VectorBaseType:TypeFundamentalType:voidArithmeticTypeArithmeticType:boolbyteubyteshortushortintuintlongulongcentucentcharwchardcharfloatdoublerealifloatidoubleirealcfloatcdoublecrealTypeSuffixes:TypeSuffixTypeSuffixesoptTypeSuffix:*[ ][AssignExpression][AssignExpression..AssignExpression][Type]delegateParametersMemberFunctionAttributesoptfunctionParametersFunctionAttributesoptQualifiedIdentifier:IdentifierIdentifier.QualifiedIdentifierTemplateInstanceTemplateInstance.QualifiedIdentifierIdentifier[AssignExpression]Identifier[AssignExpression] .QualifiedIdentifier
| Keyword | Default Initializer (.init) | Description |
|---|---|---|
| void | no default initializer | void has no value |
| bool | false | boolean value |
| byte | 0 | signed 8 bits |
| ubyte | 0u | unsigned 8 bits |
| short | 0 | signed 16 bits |
| ushort | 0u | unsigned 16 bits |
| int | 0 | signed 32 bits |
| uint | 0u | unsigned 32 bits |
| long | 0L | signed 64 bits |
| ulong | 0uL | unsigned 64 bits |
| 0 | signed 128 bits | |
| 0u | unsigned 128 bits | |
| float | float.nan | 32 bit floating point |
| double | double.nan | 64 bit floating point |
| real | real.nan | largest floating point size available |
| ifloat.nan | imaginary float | |
| idouble.nan | imaginary double | |
| ireal.nan | imaginary real | |
| cfloat.nan | a complex number of two float values | |
| cdouble.nan | complex double | |
| creal.nan | complex real | |
| char | '\xFF' | unsigned 8 bit (UTF-8 code unit) |
| wchar | '\uFFFF' | unsigned 16 bit (UTF-16 code unit) |
| dchar | '\U0000FFFF' | unsigned 32 bit (UTF-32 code unit) |
| typeof(null) | null | type of the null literal |
| typeof(*null) | assert(0) | bottom type that has no values |
Endianness of basic types is part of theABI
int* p;// pointerint[2] sa;// static arrayint[] da;// dynamic array/sliceint[string] aa;// associative arrayvoidfunction() fp;// function pointerimport std.meta : AliasSeq;AliasSeq!(int, string) tsi;// type sequence instance
A pointer value is a memory address. A pointer to typeT has a value which is a reference to an instance of typeT. It is commonly called apointer to T and its type isT*. To access the pointed-to value, use the* dereference operator:
int* p;assert(p ==null);p =newint(5);assert(p !=null);assert(*p == 5);(*p)++;assert(*p == 6);
If a pointer has anull value, it is not pointing to valid data.
When a pointer toT is dereferenced, it must either have anull value, or point to a valid instance of typeT.
To set a pointer to point at an existinglvalue, use the&address of operator:
int i = 2;int* p = &i;assert(p == &i);assert(*p == 2);*p = 4;assert(i == 4);
See also:
Anypointer implicitly converts to avoid pointer - see below.
Casting between pointers and non-pointers is allowed. Some pointer casts are disallowed in@safe code.
Implicit conversions are used to automatically convert types as required. The rules for integers are detailed in the next sections.
void main(){ noreturn n;int i = n;void* p = &i;constint[] a;const(void)[] cv = a;//void[] va = a; // error}void f(int x)pure;voidfunction(int) fp = &f;// pure is covariant with non-pure
See also Implicit Qualifier Conversions.
A derived class can be implicitly converted to its base class, but going the other way requires anexplicit cast. For example:
class Base {}class Derived : Base {}Base bd =new Derived();// implicit conversionDerived db =cast(Derived)new Base();// explicit conversion
A dynamic array, sayx, of a derived class can be implicitly converted to a dynamic array, sayy, of a base class iff elements ofx andy are qualified as being either bothconst or bothimmutable.
class Base {}class Derived : Base {}const(Base)[] ca = (const(Derived)[]).init;// `const` elementsimmutable(Base)[] ia = (immutable(Derived)[]).init;// `immutable` elements
A static array, sayx, of a derived class can be implicitly converted to a static array, sayy, of a base class iff elements ofx andy are qualified as being either bothconst or bothimmutable or both mutable (neitherconst norimmutable).
class Base {}class Derived : Base {}Base[3] ma = (Derived[3]).init;// mutable elementsconst(Base)[3] ca = (const(Derived)[3]).init;// `const` elementsimmutable(Base)[3] ia = (immutable(Derived)[3]).init;// `immutable` elements
Integer Promotions are conversions of the following types:
| from | to |
|---|---|
| bool | int |
| byte | int |
| ubyte | int |
| short | int |
| ushort | int |
| char | int |
| wchar | int |
| dchar | uint |
If an enum has as a base type one of the types in the left column, it is converted to the type in the right column.
Integer promotion applies to each operand of a binary expression:
void fun(){byte a;auto b = a + a;staticassert(is(typeof(b) ==int));// error: can't implicitly convert expression of type int to byte://byte c = a + a;ushort d;// error: can't implicitly convert expression of type int to ushort://d = d * d;int e = d * d;// OKstaticassert(is(typeof(int() * d) ==int));dchar f;staticassert(is(typeof(f - f) ==uint));}
The usual arithmetic conversions convert operands of binary operators to a common type. The operands must already be of arithmetic types. The following rules are applied in order, looking at the base type:
Example: Signed and unsigned conversions:
int i;uint u;staticassert(is(typeof(i + u) ==uint));staticassert(is(typeof(short() + u) ==uint));staticassert(is(typeof(ulong() + i) ==ulong));staticassert(is(typeof(long() - u) ==long));staticassert(is(typeof(long() *ulong()) ==ulong));
Example: Floating point:
float f;staticassert(is(typeof(f +ulong()) ==float));double d;staticassert(is(typeof(f * d) ==double));staticassert(is(typeof(real() / d) ==real));
If one or both of the operand types is anenum after undergoing the above conversions, the result type is determined as follows:
enum E { a, b, c }enum F { x, y }void test(){ E e = E.a; e = e | E.c;//e = e + 4; // error, can't assign int to Eint i = e + 4; e += 4;// OK, see below F f;//f = e | f; // error, can't assign int to F i = e | f;}
An integer of typeI implicitly converts to another integer typeJ whenJ.sizeof >= I.sizeof.
void f(byte b,ubyte ub,short s){ b = ub;// OK, bit pattern same ub = b;// OK, bit pattern same s = b;// OK, widening conversion b = s;// error, implicit narrowing}
Integer values cannot be implicitly converted to another type that cannot represent the integer bit pattern afterintegral promotion. For example:
ubyte u1 = -1;// error, -1 cannot be represented in a ubyteushort u2 = -1;// error, -1 cannot be represented in a ushortuint u3 = -1;// ok, -1 can be represented in an int, which can be converted to a uintulong u4 = -1;// ok, -1 can be represented in a long, which can be converted to a ulong
void f(int i,float f){ f = i;// OK i = f;// error}
Besides type-based implicit conversions, D allows certain integer expressions to implicitly convert to a narrower type after integer promotion. This works by analysing the minimum and maximum possible range of values for each expression. If that range of values matches or is a subset of a narrower target type's value range, implicit conversion is allowed. If a subexpression is known at compile-time, that can further narrow the range of values.
void fun(char c,int i,ubyte b){// min is c.min + 100 > short.min// max is c.max + 100 < short.maxshort s = c + 100;// OKubyte j = i & 0x3F;// OK, 0 ... 0x3F//ubyte k = i & 0x14A; // error, 0x14A > ubyte.maxushort k = i & 0x14A;// OK k = i & b;// OK, 0 ... b.max//b = b + b; // error, b.max + b.max > b.max s = b + b;// OK, 0 ... b.max + b.max}
Note the implementation does not track the range of possible values for mutable variables:
void fun(int i){ushort s = i & 0xff;// OK// s is now assumed to be s.min ... s.max, not 0 ... 0xff//ubyte b = s; // errorubyte b = s & 0xff;// OKconstint c = i & 0xff;// c's range is fixed and known b = c;// OK}
Avoid value cannot be accessed directly. Thevoid type is notably used for:
void.sizeof is 1 (not 0).
The bool type is a byte-size type that can only hold the valuetrue orfalse.
The only operators that directly accept operands of type bool are:&,|,^,&=,|=,^=, !,&&,||, and?:.
Abool value can be implicitly converted to any integral type, withfalse becoming 0 andtrue becoming 1.
The numeric literals0 and1 can be implicitly converted to theboolvaluesfalse andtrue, respectively. Casting an expression tobool meanstesting!=0 for anArithmeticType, and!=null forpointers or reference types. SeeBoolean Conversion for details.
bool b = 1;// int literal converted to `true`assert(b);assert(b + b == 2);// b promoted to intbyte i = 2;//b = i; // Errorb =cast(bool) i;// OK, same as `i != 0`assert(b);bool* p =cast(bool*) &i;// unsafe cast// `*p` holds 0x2, an invalid bool value// reading `*p` is undefined behavior
A function type has the form:
StorageClassesoptTypeParametersFunctionAttributesopt
Function types are not included in theType grammar.A function type e.g.int(int)can be aliased.A function type is only used for type tests (see below) or as the target type of a pointer.
Instantiating a function type is illegal. Instead, a pointer to functionor delegate can be used.
A function pointer type has the following form:
TypefunctionParametersFunctionAttributesopt
void f(int);alias Fun =void(int);staticassert(is(typeof(f) == Fun));staticassert(is(Fun* ==voidfunction(int)));
TypedelegateParametersMemberFunctionAttributesopt
A delegate is an aggregate of two pieces of data, acontext pointer andafunction pointer. A valid delegate holds either:
The.ptr property of a delegate will return thecontext pointer value as avoid*.
The.funcptr property of a delegate will return thefunction pointer value as a function type.
Delegates are declared and initialized similarly to function pointers:
void func(int) {}voidfunction(int) fp;// fp is a function pointervoiddelegate(int) dg;// dg is a delegate to a functionclass OB{void member(int) {}}void main(){ OB o =new OB; fp = &func;// fp points to function `func` dg = &o.member;// dg is a delegate to object `o` and member function `member`assert(dg.ptr ==cast(void*) o);assert(dg.funcptr == &OB.member); dg = (int i) { o.member(i); };// dg holds a delegate literal with main's execution context}
Delegates cannot be initialized with static member functions or non-member functions.
Delegates are called analogously to function pointers:
fp(3);// call func(3)dg(3);// call o.member(3)
See:
The equivalent of member function pointers can be constructed usinganonymous lambda functions:
class C{int a;int foo(int i) {return i + a; }}// mfp is the member function pointerauto mfp =function(C self,int i) {return self.foo(i); };auto c =new C();// create an instance of Cmfp(c, 1);// and call c.foo(1)
Typeof:typeof (Expression)typeof (return)
The first form gives the type of an expression. It can be used anywhere aBasicType is expected, such as in a declaration. It is also useful as aPrimaryExpression in a sub-expression. For example:
void func(int i){typeof(i) j;// j is of type inttypeof(3 + 6.0) x;// x is of type double// as part of a derived type:typeof(1)* p;staticassert(is(typeof(p) ==int*));typeof(p)[int] aa;staticassert(is(typeof(aa) ==int*[int]));auto d =cast(typeof(1.0)) i;// cast i to doublestaticassert(is(typeof(d) ==double));// as a sub-expression:staticassert(typeof('c').sizeof == 1);// char.sizeof Exception[2] sa; Exception ex =newtypeof(sa[0])("message");// new Exception("message")}
Expression is not evaluated, it is used purely to generate the type:
void main(){int i = 1;typeof(++i) j;// j is declared to be an int, i is not incrementedassert(i == 1);}
IfExpression is aValueSeq,typeof will produce aTypeSeq containing the types of each element.
typeof(null) is useful to get the type of thenull literal.
class A { }class B : A{typeof(this) x;// x is declared to be a Btypeof(super) y;// y is declared to be an A}struct C{statictypeof(this) z;// z is declared to be a Ctypeof(super) q;// error, no super struct for C}typeof(this) r;// error, no enclosing struct or class
If the expression is a Property Function,typeof gives its return type.
struct S{ @propertyint foo() {return 1; }}typeof(S.foo) n;// n is declared to be an int
If the expression is aTemplate,typeof gives the typevoid.
template t {}staticassert(is(typeof(t) ==void));
MixinType:mixin (ArgumentList)
EachAssignExpression in theArgumentList is evaluated at compile time, and the result must be representable as a string. The resulting strings are concatenated to form a string. The text contents of the string must be compilable as a validType, and is compiled as such.
void test(mixin("int")* p)// int* p{mixin("int")[] a;// int[] a;mixin("int[]") b;// int[] b;}
size_t is an alias to one of the unsigned integral basic types, and represents a type that is large enough to represent an offset into all addressable memory.
ptrdiff_t is an alias to the signed integral basic type the same size assize_t.
Astring is a special case of an array.
noreturn is thebottom type which can implicitly convert to any type, includingvoid. A value of typenoreturn will never be produced and the compiler can optimize such code accordingly.
noreturn.init lowers toassert(0).
A function thatnever returns has the return typenoreturn. This can occur due to e.g. an infinite loop or always throwing an exception. A function returning typenoreturn is covariant with a function returning any other type.
noreturn abort(string message);intfunction(string) fp = &abort;// OKint example(int i){if (i < 0) {// abort does not return, so it doesn't need to produce an intint val = abort("less than zero"); }// ternary expression's common type is still intreturn i != 0 ? 1024 / i : abort("calculation went awry.");}
noreturn is defined astypeof(*null). This is because dereferencing a null literal (typically) halts execution.
See also:ThrowExpression