GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing dlang.org — Types - D Programming Language Language Reference
Report a bug
If you spot a problem with this page, click here to create a GitHub issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page.
Requires a signed-in GitHub account. This works well for small changes.
If you'd like to make larger changes you may want to consider using
a local clone.
Types Contents
GrammarD 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:
TypeCtorsopt BasicType TypeSuffixesopt
TypeCtors:
TypeCtor
TypeCtor TypeCtors
TypeCtor:
const
immutable
inout
shared
BasicType:
FundamentalType
. QualifiedIdentifier
QualifiedIdentifier
Typeof
Typeof . QualifiedIdentifier
TypeCtor ( Type )
Vector
TraitsExpression
MixinType
Vector:
__vector ( VectorBaseType )
VectorBaseType:
Type
FundamentalType:
void
ArithmeticType
ArithmeticType:
bool
byte
ubyte
short
ushort
int
uint
long
ulong
cent
ucent
char
wchar
dchar
float
double
real
ifloat
idouble
ireal
cfloat
cdouble
creal
TypeSuffixes:
TypeSuffix TypeSuffixesopt
TypeSuffix:
*
[ ]
[ AssignExpression ]
[ AssignExpression .. AssignExpression ]
[ Type ]
delegate Parameters MemberFunctionAttributesopt
function Parameters FunctionAttributesopt
QualifiedIdentifier:
Identifier
Identifier . QualifiedIdentifier
TemplateInstance
TemplateInstance . QualifiedIdentifier
Identifier [ AssignExpression ]
Identifier [ AssignExpression ] . QualifiedIdentifier
Basic Data Types
Endianness of basic types is part of the ABI Implementation Defined: The real floating point type has at least the range and precision
of the double type. On x86 CPUs it is often implemented as the 80 bit Extended Real
type supported by the x86 FPU.
Note: Complex and imaginary types ifloat, idouble, ireal, cfloat, cdouble,
and creal have been deprecated in favor of std.complex.Complex.
Derived Data TypesA derived data type is a Type which either:
Types with a TypeSuffix are:
Examples: int* p; // pointer int[2] sa; // static array int[] da; // dynamic array/slice int[string] aa; // associative array void function() fp; // function pointer const(int) v = 2; // constant import std.meta : AliasSeq; AliasSeq!(int, string) tsi; // type sequence instance Note: A derived data type is distinct from a
derived class type.
Component TypesA derived data type has at least one component type:
Applying a type qualifier to a derived data type will also apply it to all its component types. See also: Pattern Matching a Derived Data Type. PointersA pointer value is a memory address. A pointer to type T has a value which is a reference to an instance of type T. It is commonly called a pointer to T and its type is T*. To access the pointed-to value, use the * dereference operator: int* p; assert(p == null); p = new int(5); assert(p != null); assert(*p == 5); (*p)++; assert(*p == 6); If a pointer has a null value, it is not pointing to valid data. When a pointer to T is dereferenced, it must either have a null value, or point to a valid instance of type T. Implementation Defined: The behavior when a null pointer is dereferenced. Typically the program
will be aborted - that is required
in @safe code.
Undefined Behavior: dereferencing a pointer that is not null and does not point
to a valid instance of type T.
To set a pointer to point at an existing lvalue, use the & address of operator: int i = 2; int* p = &i; assert(p == &i); assert(*p == 2); *p = 4; assert(i == 4); The . operator will dereference a pointer to an aggregate type instance and access a member of it. Note: There is no -> operator as in C.
See also: Best Practices: Consider using a ref function parameter or a ref local variable instead when the pointer address doesn't escape.
User-Defined TypesType ConversionsSee also: CastExpression.Pointer ConversionsCasting between pointers and non-pointers is allowed. Some pointer casts are disallowed in @safe code. Best Practices: do not cast any pointer to a non-pointer type that points to data
allocated by the garbage collector.
Implicit ConversionsImplicit conversions are used to automatically convert types as required.
void test(bool b) { short s = b; int i = s; float f = i; noreturn n(); i = n(); } void f(int x) pure; void function(int) fp = &f; // pure is covariant with non-pure See also: Class Element ConversionGiven class types T and U, and U inherits from T, the following rules apply. A pointer T* can be implicitly converted to U* if both:
Likewise, a dynamic array T[] can be implicitly converted to U[] if both:
A static array T[dim] can be implicitly converted to U[dim] if either:
class C; // inherits from Object void test() { C* pc; //Object* po = pc; // error const(Object)* po = pc; // OK, `*po` is const immutable C* pic; po = pic; C[1] sc; Object[1] so = sc; // OK, `so` can be mutable C[] ac = sc; //Object[] ao = ac; // error const Object[] ao = ac; } Rationale: These rules prevent a derived class element from being
overwritten by a base class instance.
Function Pointer ConversionsA function pointer type Source implicitly converts to another type Target if:
A conversion is covariant if the source type is more restricted than the target type. The following function pointer type conversions are covariant:
// removing function attributes pure nothrow @nogc @safe int f0(); int function() fp0 = &f0; // OK, calling fp0 can't violate f0's attributes static assert(!is(typeof(fp0) : typeof(&f0))); // cannot add attributes to fp0 // qualifying return type int* f1(); const(int*) function() fp1 = &f1; // OK, const(int*) is a subtype of int* static assert(!is(typeof(fp1) : typeof(&f1))); // cannot unqualify return type of fp1 // returning a base type int* f2(); void* function() fp2 = &f2; // OK, void* is a subtype of int* static assert(!is(typeof(fp2) : typeof(&f2))); // fp2 cannot return subtype A conversion is contravariant if the source type is more general than the target type. The following conversions are contravariant:
Note: A const parameter is more general than a mutable one because
it accepts both mutable and const arguments.
See also return attribute variance. // unqualifying a parameter void f3(const int*); void function(int*) fp3 = &f3; // OK static assert(!is(typeof(fp3) : typeof(&f3))); // cannot qualify parameter See also: Integer PromotionsInteger Promotions are conversions of the following types:
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; static assert(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; // OK static assert(is(typeof(int() * d) == int)); dchar f; static assert(is(typeof(f - f) == uint)); } Rationale:
Usual Arithmetic ConversionsThe 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:
Rationale: The above rules follow C99, which makes porting code from C easier.
Example: Signed and unsigned conversions: int i; uint u; static assert(is(typeof(i + u) == uint)); static assert(is(typeof(short() + u) == uint)); static assert(is(typeof(ulong() + i) == ulong)); static assert(is(typeof(long() - u) == long)); static assert(is(typeof(long() * ulong()) == ulong)); Example: Floating point: float f; static assert(is(typeof(f + ulong()) == float)); double d; static assert(is(typeof(f * d) == double)); static assert(is(typeof(real() / d) == real)); Enum OperationsIf one or both of the operand types is an enum 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 E int i = e + 4; e += 4; // OK, see below F f; //f = e | f; // error, can't assign int to F i = e | f; } Integer Type ConversionsAn integer of type I implicitly converts to another integer type J when J.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 after integral promotion. For example: ubyte u1 = -1; // error, -1 cannot be represented in a ubyte ushort u2 = -1; // error, -1 cannot be represented in a ushort uint u3 = -1; // ok, -1 can be represented in an int, which can be converted to a uint ulong u4 = -1; // ok, -1 can be represented in a long, which can be converted to a ulong Floating Point Type Conversions
void f(int i, float f) { f = i; // OK i = f; // error }
Value Range PropagationBesides 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.max short s = c + 100; // OK ubyte j = i & 0x3F; // OK, 0 ... 0x3F //ubyte k = i & 0x14A; // error, 0x14A > ubyte.max ushort 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; // error ubyte b = s & 0xff; // OK const int c = i & 0xff; // c's range is fixed and known b = c; // OK }
voidA void value cannot be accessed directly. The void type is notably used for:
void f(); static assert(is(typeof(f()) == void)); void* ptr; static assert(is(typeof(ptr[0]) == void)); template t() {} static assert(is(typeof(t) == void)); static assert(is(typeof(t!()) == void)); Rationale: To simplify the grammar, an expression can resolve to a template or
template instantiation. A valid expression must have a valid type.
void.sizeof is 1 (not 0). Rationale: The size must be 1 to make void* arithmetic work like it does in C.
It also makes the length of a void array equivalent to the number of
bytes in the array.
boolThe bool type is a byte-size type that can only hold the value true or false. The only operators that directly accept operands of type bool are: &, |, ^, &=, |=, ^=, !, &&, ||, and ?:. A bool value can be implicitly converted to any integral type, with false becoming 0 and true becoming 1. The numeric literals 0 and 1 can be implicitly converted to the bool values false and true, respectively. Casting an expression to bool means testing !=0 for an ArithmeticType, and !=null for pointers or reference types. See Boolean Conversion for details. Undefined Behavior:
bool b = 1; // int literal converted to `true` assert(b); assert(b + b == 2); // b promoted to int byte i = 2; //b = i; // Error b = 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 Function TypesA function type has the form: StorageClassesopt Type Parameters FunctionAttributesopt Function types are not included in the Type 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 function or delegate can be used. Function PointersA function pointer type has the following form: Type function Parameters FunctionAttributesopt void f(int); alias Fun = void(int); static assert(is(typeof(f) == Fun)); static assert(is(Fun* == void function(int))); See Function Pointers. DelegatesType delegate Parameters MemberFunctionAttributesopt A delegate is an aggregate of two pieces of data, a context pointer and a function pointer. A valid delegate holds either:
The .ptr property of a delegate will return the context pointer value as a void*. The .funcptr property of a delegate will return the function pointer value as a function type. Delegates are declared and initialized similarly to function pointers: void func(int) {} void function(int) fp; // fp is a function pointer void delegate(int) dg; // dg is a delegate to a function class 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 using anonymous lambda functions: class C { int a; int foo(int i) { return i + a; } } // mfp is the member function pointer auto mfp = function(C self, int i) { return self.foo(i); }; auto c = new C(); // create an instance of C mfp(c, 1); // and call c.foo(1) typeofTypeof:
typeof ( Expression )
typeof ( return )
The first form gives the type of an expression. It can be used anywhere a BasicType is expected, such as in a declaration. It is also useful as a PrimaryExpression in a sub-expression. For example: void func(int i) { typeof(i) j; // j is of type int typeof(3 + 6.0) x; // x is of type double // as part of a derived type: typeof(1)* p; static assert(is(typeof(p) == int*)); typeof(p)[int] aa; static assert(is(typeof(aa) == int*[int])); auto d = cast(typeof(1.0)) i; // cast i to double static assert(is(typeof(d) == double)); // as a sub-expression: static assert(typeof('c').sizeof == 1); // char.sizeof Exception[2] sa; Exception ex = new typeof(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 incremented assert(i == 1); } If Expression is a ValueSeq, typeof will produce a TypeSeq containing the types of each element. typeof(null) is useful to get the type of the null literal. Best Practices: Typeof is most useful in writing generic
template code.
Special Cases
class A { } class B : A { typeof(this) x; // x is declared to be a B typeof(super) y; // y is declared to be an A } struct C { static typeof(this) z; // z is declared to be a C typeof(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 { @property int foo() { return 1; } } typeof(S.foo) n; // n is declared to be an int Mixin TypesMixinType:
mixin ( ArgumentList )
Each AssignExpression in the ArgumentList 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 valid Type, and is compiled as such. void test(mixin("int")* p) // int* p { mixin("int")[] a; // int[] a; mixin("int[]") b; // int[] b; } Aliased Typessize_tsize_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_tptrdiff_t is an alias to the signed integral basic type the same size as size_t. stringA string is a special case of an array. noreturnnoreturn is the bottom type which can implicitly convert to any type, including void. A value of type noreturn will never be produced and the compiler can optimize such code accordingly. noreturn.init lowers to assert(0). A function that never returns has the return type noreturn. This can occur due to e.g. an infinite loop or always throwing an exception. A function returning type noreturn is covariant with a function returning any other type. noreturn abort(string message); int function(string) fp = &abort; // OK int example(int i) { if (i < 0) { // abort does not return, so it doesn't need to produce an int int val = abort("less than zero"); } // ternary expression's common type is still int return i != 0 ? 1024 / i : abort("calculation went awry."); } noreturn is defined as typeof(*null). This is because dereferencing a null literal (typically) halts execution. See also: ThrowExpression )Copyright © 1999-2026 by the D Language Foundation | Page generated by
Ddoc on Mon Nov 9 05:59:18 2026
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |