erased-subject.dhover×407all
#!/usr/bin/env dub
/+ dub.sdl:
    name "property_tree_erased_subject"
    targetPath "build"
    dflags "-preview=in" "-preview=dip1000"
    buildType "checked" {
        buildOptions "optimize" "inline" "debugInfo"
    }
+/
/**
 * One walk, two worlds (fork D1, as decided): the API is static
 * introspection, and a DYNAMIC subject is served by a statically-typed
 * erasure — a `JsonValue`-shaped type that supplies its children at run time
 * through a capability the walk detects by presence.
 *
 * Under test:
 *   C16. `propChildren` (an `opApply` yielding `(name, ref child)`) is enough:
 *        a type that has it enumerates its own children; a type that does not
 *        is walked with `__traits`. One walk, no branch in the caller, no
 *        registry — the toolkit's capability-by-presence idiom.
 *   C17. A MIXED subject works: a plain struct with a `Dyn` field descends
 *        from static fields into dynamic ones and back, with one path syntax
 *        across the seam.
 *   C18. Arrays are children too, addressed `[i]`, in both worlds.
 *   C19. The capability also carries what static reflection cannot: the
 *        dynamic type states its own leaf presentation and whether it is
 *        expandable, so the row model needs no special case for it.
 *
 * Run: `dub run --single erased-subject.d`
 */
module 
(module) property_tree_erased_subject

One walk, two worlds (fork D1, as decided): the API is static introspection, and a DYNAMIC subject is served by a statically-typed erasure — a JsonValue-shaped type that supplies its children at run time through a capability the walk detects by presence.

Under test: C16. propChildren (an opApply yielding (name, ref child)) is enough: a type that has it enumerates its own children; a type that does not is walked with __traits. One walk, no branch in the caller, no registry — the toolkit's capability-by-presence idiom. C17. A MIXED subject works: a plain struct with a Dyn field descends from static fields into dynamic ones and back, with one path syntax across the seam. C18. Arrays are children too, addressed [i], in both worlds. C19. The capability also carries what static reflection cannot: the dynamic type states its own leaf presentation and whether it is expandable, so the row model needs no special case for it.

Run

dub run --single erased-subject.d

property_tree_erased_subject
;
import
(package) std
std
.
(module) std.conv

A one-stop shop for converting values from one type to another.

Category Functions
Generic asOriginalType castFrom parse to toChars bitCast
Strings text wtext dtext writeText writeWText writeDText hexString
Numeric octal roundTo signed unsigned
Exceptions ConvException ConvOverflowException

Source

std/conv.d

@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Shin Fujishiro, Adam D. Ruppe, Kenji Hara
conv
:
(alias template) property_tree_erased_subject.text = std.conv.text(T...)(T args) if (T.length > 0)

Convenience functions for converting one or more arguments of any type into text (the three character widths).

text
,
(alias template) property_tree_erased_subject.to = std.conv.to(T)

The to template converts a value from one type to another. The source type is deduced and the target type must be specified, for example the expression to`!int(42.0)` converts the number 42 from `double` to `int`. The conversion is "safe", i.e., it checks for overflow; to!int(4.2e10) would throw the ConvOverflowException exception. Overflow checks are only inserted when necessary, e.g., ``to!double(42) does not do any checking because any int fits in a double.

Conversions from string to numeric types differ from the C equivalents atoi() and atol() by checking for overflow and not allowing whitespace.

For conversion of strings to signed types, the grammar recognized is: Integer: Sign UnsignedInteger UnsignedInteger Sign: + -

For conversion to unsigned types, the grammar recognized is: UnsignedInteger: DecimalDigit DecimalDigit UnsignedInteger

to
;
import
(package) std
std
.
(module) std.traits

Templates which extract information about types and symbols at compile time.

Category Templates
Symbol Name traits fullyQualifiedName mangledName moduleName packageName
Function traits isFunction arity functionAttributes hasFunctionAttributes functionLinkage FunctionTypeOf isSafe isUnsafe isFinal ParameterDefaults ParameterIdentifierTuple ParameterStorageClassTuple Parameters ReturnType SetFunctionAttributes variadicFunctionStyle
Aggregate Type traits BaseClassesTuple BaseTypeTuple classInstanceAlignment EnumMembers FieldNameTuple Fields hasAliasing hasElaborateAssign hasElaborateCopyConstructor hasElaborateDestructor hasElaborateMove hasIndirections hasMember hasStaticMember hasNested hasUnsharedAliasing InterfacesTuple isInnerClass isNested MemberFunctionsTuple RepresentationTypeTuple TemplateArgsOf TemplateOf TransitiveBaseTypeTuple
Type Conversion CommonType AllImplicitConversionTargets ImplicitConversionTargets CopyTypeQualifiers CopyConstness isAssignable isCovariantWith isImplicitlyConvertible isQualifierConvertible
Type Constructors InoutOf ConstOf SharedOf SharedInoutOf SharedConstOf SharedConstInoutOf ImmutableOf QualifierOf
Categories of types allSameType ifTestable isType isAggregateType isArray isAssociativeArray isAutodecodableString isBasicType isBoolean isBuiltinType isCopyable isDynamicArray isEqualityComparable isFloatingPoint isIntegral isNarrowString isConvertibleToString isNumeric isOrderingComparable isPointer isScalarType isSigned isSIMDVector isSomeChar isSomeString isStaticArray isUnsigned
Type behaviours isAbstractClass isAbstractFunction isCallable isDelegate isExpressions isFinalClass isFinalFunction isFunctionPointer isInstanceOf isIterable isMutable isSomeFunction isTypeTuple
General Types ForeachType KeyType Largest mostNegative OriginalType PointerTarget Signed Unconst Unshared Unqual Unsigned ValueType Promoted
Misc lvalueOf rvalueOf Select select
User-Defined Attributes hasUDA getUDAs getSymbolsByUDA

Source

std/traits.d

@copyrightCopyright The D Language Foundation 2005 - 2009.@licenseBoost License 1.0.@authorsWalter Bright, Tomasz Stachowiak (isExpressions), Andrei Alexandrescu, Shin Fujishiro, Robert Clipsham, David Nadlinger, Kenji Hara, Shoichi Kato
traits
:
(alias template) property_tree_erased_subject.isAggregateType = std.traits.isAggregateType(T)

Detect whether type T is an aggregate type.

isAggregateType
,
(alias template) property_tree_erased_subject.isArray = std.traits.isArray(T)

Detect whether type T is an array (static or dynamic; for associative arrays see isAssociativeArray).

isArray
,
(alias template) property_tree_erased_subject.isAssociativeArray = std.traits.isAssociativeArray(T)

Detect whether T is an associative array type

See also: __traits(isAssociativeArray, T)

isAssociativeArray
,
(alias template) property_tree_erased_subject.isSomeString = std.traits.isSomeString(T)

Detect whether T is one of the built-in string types.

The built-in string types are Char[], where Char is any of char, wchar or dchar, with or without qualifiers.

Static arrays of characters (like char[80]) are not considered built-in string types.

isSomeString
;
@safe: // ── the type-erased value (the "JsonValue" position) ───────────────────────── struct
(struct) property_tree_erased_subject.Dyn
Dyn
{ enum
(enum) property_tree_erased_subject.Dyn.Kind
Kind
: ubyte {
(enum value) property_tree_erased_subject.Dyn.Kind.nil = cast(ubyte)0u
nil
,
(enum value) property_tree_erased_subject.Dyn.Kind.boolean = 1
boolean
,
(enum value) property_tree_erased_subject.Dyn.Kind.number = 2
number
,
(enum value) property_tree_erased_subject.Dyn.Kind.str = 3
str
,
(enum value) property_tree_erased_subject.Dyn.Kind.array = 4
array
,
(enum value) property_tree_erased_subject.Dyn.Kind.object = 5
object
}
(enum) property_tree_erased_subject.Dyn.Kind
Kind
(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kind
kind
;
bool
(field) bool property_tree_erased_subject.Dyn.b
b
;
double
(field) double property_tree_erased_subject.Dyn.num
num
;
(alias) object.string = string
string
(field) string property_tree_erased_subject.Dyn.s
s
;
(struct) property_tree_erased_subject.Dyn
Dyn
[]
(field) property_tree_erased_subject.Dyn[] property_tree_erased_subject.Dyn.items
items
;
(struct) property_tree_erased_subject.Dyn.Pair
Pair
[]
(field) property_tree_erased_subject.Dyn.Pair[] property_tree_erased_subject.Dyn.fields
fields
;
static struct
(struct) property_tree_erased_subject.Dyn.Pair
Pair
{
(alias) object.string = string
string
(field) string property_tree_erased_subject.Dyn.Pair.key
key
;
(struct) property_tree_erased_subject.Dyn
Dyn
(field) property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.Pair.value
value
; }
static
(struct) property_tree_erased_subject.Dyn
Dyn
property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.of(bool v) @safe
of
(bool
(parameter) bool v
v
) {
(struct) property_tree_erased_subject.Dyn
Dyn
(local variable) property_tree_erased_subject.Dyn d
d
;
(local variable) property_tree_erased_subject.Dyn d
d
.
(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kind
kind
=
(enum) property_tree_erased_subject.Dyn.Kind
Kind
.
(enum value) property_tree_erased_subject.Dyn.Kind.boolean = 1
boolean
;
(local variable) property_tree_erased_subject.Dyn d
d
.
(field) bool property_tree_erased_subject.Dyn.b
b
=
(parameter) bool v
v
; return
(local variable) property_tree_erased_subject.Dyn d
d
; }
static
(struct) property_tree_erased_subject.Dyn
Dyn
property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.of(double v) @safe
of
(double
(parameter) double v
v
) {
(struct) property_tree_erased_subject.Dyn
Dyn
(local variable) property_tree_erased_subject.Dyn d
d
;
(local variable) property_tree_erased_subject.Dyn d
d
.
(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kind
kind
=
(enum) property_tree_erased_subject.Dyn.Kind
Kind
.
(enum value) property_tree_erased_subject.Dyn.Kind.number = 2
number
;
(local variable) property_tree_erased_subject.Dyn d
d
.
(field) double property_tree_erased_subject.Dyn.num
num
=
(parameter) double v
v
; return
(local variable) property_tree_erased_subject.Dyn d
d
; }
static
(struct) property_tree_erased_subject.Dyn
Dyn
property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.of(string v) @safe
of
(
(alias) object.string = string
string
(parameter) string v
v
) {
(struct) property_tree_erased_subject.Dyn
Dyn
(local variable) property_tree_erased_subject.Dyn d
d
;
(local variable) property_tree_erased_subject.Dyn d
d
.
(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kind
kind
=
(enum) property_tree_erased_subject.Dyn.Kind
Kind
.
(enum value) property_tree_erased_subject.Dyn.Kind.str = 3
str
;
(local variable) property_tree_erased_subject.Dyn d
d
.
(field) string property_tree_erased_subject.Dyn.s
s
=
(parameter) string v
v
; return
(local variable) property_tree_erased_subject.Dyn d
d
; }
static
(struct) property_tree_erased_subject.Dyn
Dyn
property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.arr(property_tree_erased_subject.Dyn[] v) @safe
arr
(
(struct) property_tree_erased_subject.Dyn
Dyn
[]
(parameter) property_tree_erased_subject.Dyn[] v
v
) {
(struct) property_tree_erased_subject.Dyn
Dyn
(local variable) property_tree_erased_subject.Dyn d
d
;
(local variable) property_tree_erased_subject.Dyn d
d
.
(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kind
kind
=
(enum) property_tree_erased_subject.Dyn.Kind
Kind
.
(enum value) property_tree_erased_subject.Dyn.Kind.array = 4
array
;
(local variable) property_tree_erased_subject.Dyn d
d
.
(field) property_tree_erased_subject.Dyn[] property_tree_erased_subject.Dyn.items
items
=
(parameter) property_tree_erased_subject.Dyn[] v
v
; return
(local variable) property_tree_erased_subject.Dyn d
d
; }
static
(struct) property_tree_erased_subject.Dyn
Dyn
property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.obj(property_tree_erased_subject.Dyn.Pair[] v) @safe
obj
(
(struct) property_tree_erased_subject.Dyn.Pair
Pair
[]
(parameter) property_tree_erased_subject.Dyn.Pair[] v
v
){
(struct) property_tree_erased_subject.Dyn
Dyn
(local variable) property_tree_erased_subject.Dyn d
d
;
(local variable) property_tree_erased_subject.Dyn d
d
.
(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kind
kind
=
(enum) property_tree_erased_subject.Dyn.Kind
Kind
.
(enum value) property_tree_erased_subject.Dyn.Kind.object = 5
object
;
(local variable) property_tree_erased_subject.Dyn d
d
.
(field) property_tree_erased_subject.Dyn.Pair[] property_tree_erased_subject.Dyn.fields
fields
=
(parameter) property_tree_erased_subject.Dyn.Pair[] v
v
; return
(local variable) property_tree_erased_subject.Dyn d
d
; }
// ── the capability (C16/C19) ───────────────────────────────────────────── /// Children, named. `name` is a member name for an object and `null` for /// an array element (the walk supplies the `[i]` form). auto
property_tree_erased_subject.Dyn.propChildren.Range property_tree_erased_subject.Dyn.propChildren() pure nothrow @nogc return @safe

Children, named. name is a member name for an object and null for an array element (the walk supplies the [i] form).

propChildren
() return
{ static struct
(struct) property_tree_erased_subject.Dyn.propChildren.Range
Range
{
(struct) property_tree_erased_subject.Dyn
Dyn
*
(field) property_tree_erased_subject.Dyn* property_tree_erased_subject.Dyn.propChildren.Range.self
self
;
int
int property_tree_erased_subject.Dyn.propChildren.Range.opApply(scope int delegate(ulong, const(char)[], ref property_tree_erased_subject.Dyn) @safe dg) @safe
opApply
(scope int delegate(
(alias) object.size_t = ulong
size_t
, const(char)[], ref
(struct) property_tree_erased_subject.Dyn
Dyn
) @safe
(parameter) int delegate(ulong, const(char)[], ref property_tree_erased_subject.Dyn) @safe dg
dg
)
{ if (
(field) property_tree_erased_subject.Dyn* property_tree_erased_subject.Dyn.propChildren.Range.self
self
.
(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kind
kind
==
(enum) property_tree_erased_subject.Dyn.Kind
Kind
.
(enum value) property_tree_erased_subject.Dyn.Kind.object = 5
object
)
foreach (
(parameter) ulong i
i
, ref
(parameter) property_tree_erased_subject.Dyn.Pair f
f
;
(field) property_tree_erased_subject.Dyn* property_tree_erased_subject.Dyn.propChildren.Range.self
self
.
(field) property_tree_erased_subject.Dyn.Pair[] property_tree_erased_subject.Dyn.fields
fields
)
{ if (auto
(local variable) int r
r
=
(parameter) int delegate(ulong, const(char)[], ref property_tree_erased_subject.Dyn) @safe dg
dg
(
(local variable) ulong i
i
,
(local variable) property_tree_erased_subject.Dyn.Pair f
f
.
(field) string property_tree_erased_subject.Dyn.Pair.key
key
,
(local variable) property_tree_erased_subject.Dyn.Pair f
f
.
(field) property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.Pair.value
value
)) return
(local variable) int r
r
;
} else if (
(field) property_tree_erased_subject.Dyn* property_tree_erased_subject.Dyn.propChildren.Range.self
self
.
(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kind
kind
==
(enum) property_tree_erased_subject.Dyn.Kind
Kind
.
(enum value) property_tree_erased_subject.Dyn.Kind.array = 4
array
)
foreach (
(parameter) ulong i
i
, ref
(parameter) property_tree_erased_subject.Dyn v
v
;
(field) property_tree_erased_subject.Dyn* property_tree_erased_subject.Dyn.propChildren.Range.self
self
.
(field) property_tree_erased_subject.Dyn[] property_tree_erased_subject.Dyn.items
items
)
{ if (auto
(local variable) int r
r
=
(parameter) int delegate(ulong, const(char)[], ref property_tree_erased_subject.Dyn) @safe dg
dg
(
(local variable) ulong i
i
, null,
(local variable) property_tree_erased_subject.Dyn v
v
)) return
(local variable) int r
r
;
} return 0; } } return () @trusted { return
(struct) property_tree_erased_subject.Dyn.propChildren.Range
Range
(&this); }();
} /// The rest of the capability: is this expandable, and how does it read? bool
bool property_tree_erased_subject.Dyn.propExpandable() const pure nothrow @nogc @safe

The rest of the capability: is this expandable, and how does it read?

propExpandable
() const pure nothrow @nogc
=>
(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kind
kind
==
(enum) property_tree_erased_subject.Dyn.Kind
Kind
.
(enum value) property_tree_erased_subject.Dyn.Kind.object = 5
object
||
(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kind
kind
==
(enum) property_tree_erased_subject.Dyn.Kind
Kind
.
(enum value) property_tree_erased_subject.Dyn.Kind.array = 4
array
;
(alias) object.string = string
string
string property_tree_erased_subject.Dyn.propText() const pure @safe
propText
() const pure
{ final switch (
(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kind
kind
)
{ case
(enum) property_tree_erased_subject.Dyn.Kind
Kind
.
(enum value) property_tree_erased_subject.Dyn.Kind.nil = cast(ubyte)0u
nil
: return "null";
case
(enum) property_tree_erased_subject.Dyn.Kind
Kind
.
(enum value) property_tree_erased_subject.Dyn.Kind.boolean = 1
boolean
: return
(field) bool property_tree_erased_subject.Dyn.b
b
? "true" : "false";
case
(enum) property_tree_erased_subject.Dyn.Kind
Kind
.
(enum value) property_tree_erased_subject.Dyn.Kind.number = 2
number
: return
(field) double property_tree_erased_subject.Dyn.num
num
.
string std.conv.to!string.to!(const(double))(const(double) __param_0) pure @safe

The to template converts a value from one type to another. The source type is deduced and the target type must be specified, for example the expression to`!int(42.0)` converts the number 42 from `double` to `int`. The conversion is "safe", i.e., it checks for overflow; to!int(4.2e10) would throw the ConvOverflowException exception. Overflow checks are only inserted when necessary, e.g., ``to!double(42) does not do any checking because any int fits in a double.

Conversions from string to numeric types differ from the C equivalents atoi() and atol() by checking for overflow and not allowing whitespace.

For conversion of strings to signed types, the grammar recognized is: Integer: Sign UnsignedInteger UnsignedInteger Sign: + -

For conversion to unsigned types, the grammar recognized is: UnsignedInteger: DecimalDigit DecimalDigit UnsignedInteger

Examples

Converting a value to its own type (useful mostly for generic code) simply returns its argument.

int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14

Converting among numeric types is a safe way to cast them around.

Conversions from floating-point types to integral types allow loss of precision (the fractional part of a floating-point number). The conversion is truncating towards zero, the same way a cast would truncate. (To round a floating point value when casting to an integral, use roundTo.)

import std.exception : assertThrown;

int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));

assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);

When converting strings to numeric types, note that D hexadecimal and binary literals are not handled. Neither the prefixes that indicate the base, nor the horizontal bar used to separate groups of digits are recognized. This also applies to the suffixes that indicate the type.

To work around this, you can specify a radix for conversions involving numbers.

auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);

Conversions from integral types to floating-point types always succeed, but might lose accuracy. The largest integers with a predecessor representable in floating-point format are 2^24-1 for float, 2^53-1 for double, and 2^64-1 for real (when real is 80-bit, e.g. on Intel machines).

// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);

Conversion from string types to char types enforces the input to consist of a single code point, and said code point must fit in the target type. Otherwise, ConvException is thrown.

import std.exception : assertThrown;

assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');

// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');

// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));

Converting an array to another array type works by converting each element in turn. Associative arrays can be converted to associative arrays as long as keys and values can in turn be converted.

import std.string : split;

int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);

Conversions operate transitively, meaning that they work on arrays and associative arrays of any complexity.

This conversion works because to`!short` applies to an `int`, to!wstring applies to a string, to`!string` applies to a `double`, and to!(double[]) applies to an int[]. The conversion might throw an exception because ``to!short might fail the range check.

int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);

Object-to-object conversions by dynamic casting throw exception when the source is non-null and the target is null.

import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));

Stringize conversion from all types is supported.

  • String to string conversion works for any two string types having (char, wchar, dchar) character widths and any combination of qualifiers (mutable, const, or immutable).

  • Converts array (other than strings) to string. Each element is converted by calling ``to!T.

  • Associative array to string conversion. Each element is converted by calling ``to!T.

  • Object to string conversion calls toString against the object or returns "null" if the object is null.

  • Struct to string conversion calls toString against the struct if it is defined.

  • For structs that do not define toString, the conversion to string produces the list of fields.

  • Enumerated types are converted to strings as their symbolic names.

  • Boolean values are converted to "true" or "false".

  • char, wchar, dchar to a string type.

  • Unsigned or signed integers to strings.

    special case

    : Convert integral value to string in radix radix. radix must be a value from 2 to 36. value is treated as a signed value only if radix is 10. The characters A through Z are used to represent values 10 through 36 and their case is determined by the letterCase parameter.

  • All floating point types to all string types.

  • Pointer to string conversions convert the pointer to a size_t value. If pointer is char*, treat it as C-style strings. In that case, this function is @system.

See formatValue on how toString should be defined.

// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");

// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
       to!string(associativeArray) == `["1":2, "0":1]`);

// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");

// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);

auto c = to!(wchar[])(b);
assert(c == "abcx");

Strings can be converted to enum types. The enum member with the same name as the input string is returned. The comparison is case-sensitive.

A ConvException is thrown if the enum does not have the specified member.

import std.exception : assertThrown;

enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to
!
(alias) object.string = string
string
;
case
(enum) property_tree_erased_subject.Dyn.Kind
Kind
.
(enum value) property_tree_erased_subject.Dyn.Kind.str = 3
str
: return `"` ~
(field) string property_tree_erased_subject.Dyn.s
s
~ `"`;
case
(enum) property_tree_erased_subject.Dyn.Kind
Kind
.
(enum value) property_tree_erased_subject.Dyn.Kind.array = 4
array
: return
string std.conv.text!(string, ulong, string)(string __param_0, ulong __param_1, string __param_2) pure nothrow @safe

Convenience functions for converting one or more arguments of any type into text (the three character widths).

text
("[",
(field) property_tree_erased_subject.Dyn[] property_tree_erased_subject.Dyn.items
items
.
(field) ulong const(property_tree_erased_subject.Dyn[]).length
length
, " items]");
case
(enum) property_tree_erased_subject.Dyn.Kind
Kind
.
(enum value) property_tree_erased_subject.Dyn.Kind.object = 5
object
: return
string std.conv.text!(string, ulong, string)(string __param_0, ulong __param_1, string __param_2) pure nothrow @safe

Convenience functions for converting one or more arguments of any type into text (the three character widths).

text
("{",
(field) property_tree_erased_subject.Dyn.Pair[] property_tree_erased_subject.Dyn.fields
fields
.
(field) ulong const(property_tree_erased_subject.Dyn.Pair[]).length
length
, " keys}");
} } } // ── the one walk ───────────────────────────────────────────────────────────── struct
(struct) property_tree_erased_subject.Row
Row
{
(alias) object.string = string
string
(field) string property_tree_erased_subject.Row.path
path
;
(alias) object.string = string
string
(field) string property_tree_erased_subject.Row.label
label
;
(alias) object.string = string
string
(field) string property_tree_erased_subject.Row.type
type
;
(alias) object.string = string
string
(field) string property_tree_erased_subject.Row.value
value
; bool
(field) bool property_tree_erased_subject.Row.expandable
expandable
; }
enum bool
(constant) bool property_tree_erased_subject.hasPropChildren!(property_tree_erased_subject.Config) = false
hasPropChildren
(T) = __traits(compiles,
(ref
(alias) T = property_tree_erased_subject.Config
T
(parameter) property_tree_erased_subject.Config t
t
) { foreach (
(parameter) i
i
,
(parameter) name
name
, ref
(parameter) child
child
;
(parameter) property_tree_erased_subject.Config t
t
.
property_tree_erased_subject.Dyn.propChildren.Range property_tree_erased_subject.Dyn.propChildren() pure nothrow @nogc return @safe

Children, named. name is a member name for an object and null for an array element (the walk supplies the [i] form).

propChildren
) {} });
void
void property_tree_erased_subject.walk!(property_tree_erased_subject.Config)(ref property_tree_erased_subject.Config v, ref property_tree_erased_subject.Row[] rows, string path, string label, int depth, int maxDepth) @safe
walk
(T)(ref
(alias) T = property_tree_erased_subject.Config
T
(parameter) property_tree_erased_subject.Config v
v
, ref
(struct) property_tree_erased_subject.Row
Row
[]
(parameter) property_tree_erased_subject.Row[] rows
rows
,
(alias) object.string = string
string
(parameter) string path
path
,
(alias) object.string = string
string
(parameter) string label
label
, int
(parameter) int depth
depth
,
int
(parameter) int maxDepth
maxDepth
)
{ static if (
(template instance) property_tree_erased_subject.hasPropChildren!(property_tree_erased_subject.Config)
hasPropChildren
!
(alias) T = property_tree_erased_subject.Config
T
) // C16
{
(parameter) property_tree_erased_subject.Row[] rows
rows
~=
(struct) property_tree_erased_subject.Row
Row
(
(parameter) string path
path
,
(parameter) string label
label
,
(struct) property_tree_erased_subject.Dyn
T
.
(constant) string property_tree_erased_subject.Dyn.stringof = "Dyn"
stringof
,
(parameter) property_tree_erased_subject.Dyn v
v
.
string property_tree_erased_subject.Dyn.propText() const pure @safe
propText
,
(parameter) property_tree_erased_subject.Dyn v
v
.
bool property_tree_erased_subject.Dyn.propExpandable() const pure nothrow @nogc @safe

The rest of the capability: is this expandable, and how does it read?

propExpandable
);
if (
(parameter) int depth
depth
>=
(parameter) int maxDepth
maxDepth
|| !
(parameter) property_tree_erased_subject.Dyn v
v
.
bool property_tree_erased_subject.Dyn.propExpandable() const pure nothrow @nogc @safe

The rest of the capability: is this expandable, and how does it read?

propExpandable
) return;
foreach (
(foreach variable) ulong i
i
,
(foreach variable) const(char)[] name
name
, ref
(foreach variable) property_tree_erased_subject.Dyn child
child
;
(parameter) property_tree_erased_subject.Dyn v
v
.
property_tree_erased_subject.Dyn.propChildren.Range property_tree_erased_subject.Dyn.propChildren() pure nothrow @nogc return @safe

Children, named. name is a member name for an object and null for an array element (the walk supplies the [i] form).

propChildren
)
{ const
(local variable) const(string) p
p
=
(foreach variable) const(char)[] name
name
is null ?
(parameter) string path
path
~ "[" ~
(foreach variable) ulong i
i
.
string std.conv.to!string.to!ulong(ulong __param_0) pure nothrow @safe

The to template converts a value from one type to another. The source type is deduced and the target type must be specified, for example the expression to`!int(42.0)` converts the number 42 from `double` to `int`. The conversion is "safe", i.e., it checks for overflow; to!int(4.2e10) would throw the ConvOverflowException exception. Overflow checks are only inserted when necessary, e.g., ``to!double(42) does not do any checking because any int fits in a double.

Conversions from string to numeric types differ from the C equivalents atoi() and atol() by checking for overflow and not allowing whitespace.

For conversion of strings to signed types, the grammar recognized is: Integer: Sign UnsignedInteger UnsignedInteger Sign: + -

For conversion to unsigned types, the grammar recognized is: UnsignedInteger: DecimalDigit DecimalDigit UnsignedInteger

Examples

Converting a value to its own type (useful mostly for generic code) simply returns its argument.

int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14

Converting among numeric types is a safe way to cast them around.

Conversions from floating-point types to integral types allow loss of precision (the fractional part of a floating-point number). The conversion is truncating towards zero, the same way a cast would truncate. (To round a floating point value when casting to an integral, use roundTo.)

import std.exception : assertThrown;

int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));

assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);

When converting strings to numeric types, note that D hexadecimal and binary literals are not handled. Neither the prefixes that indicate the base, nor the horizontal bar used to separate groups of digits are recognized. This also applies to the suffixes that indicate the type.

To work around this, you can specify a radix for conversions involving numbers.

auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);

Conversions from integral types to floating-point types always succeed, but might lose accuracy. The largest integers with a predecessor representable in floating-point format are 2^24-1 for float, 2^53-1 for double, and 2^64-1 for real (when real is 80-bit, e.g. on Intel machines).

// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);

Conversion from string types to char types enforces the input to consist of a single code point, and said code point must fit in the target type. Otherwise, ConvException is thrown.

import std.exception : assertThrown;

assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');

// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');

// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));

Converting an array to another array type works by converting each element in turn. Associative arrays can be converted to associative arrays as long as keys and values can in turn be converted.

import std.string : split;

int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);

Conversions operate transitively, meaning that they work on arrays and associative arrays of any complexity.

This conversion works because to`!short` applies to an `int`, to!wstring applies to a string, to`!string` applies to a `double`, and to!(double[]) applies to an int[]. The conversion might throw an exception because ``to!short might fail the range check.

int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);

Object-to-object conversions by dynamic casting throw exception when the source is non-null and the target is null.

import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));

Stringize conversion from all types is supported.

  • String to string conversion works for any two string types having (char, wchar, dchar) character widths and any combination of qualifiers (mutable, const, or immutable).

  • Converts array (other than strings) to string. Each element is converted by calling ``to!T.

  • Associative array to string conversion. Each element is converted by calling ``to!T.

  • Object to string conversion calls toString against the object or returns "null" if the object is null.

  • Struct to string conversion calls toString against the struct if it is defined.

  • For structs that do not define toString, the conversion to string produces the list of fields.

  • Enumerated types are converted to strings as their symbolic names.

  • Boolean values are converted to "true" or "false".

  • char, wchar, dchar to a string type.

  • Unsigned or signed integers to strings.

    special case

    : Convert integral value to string in radix radix. radix must be a value from 2 to 36. value is treated as a signed value only if radix is 10. The characters A through Z are used to represent values 10 through 36 and their case is determined by the letterCase parameter.

  • All floating point types to all string types.

  • Pointer to string conversions convert the pointer to a size_t value. If pointer is char*, treat it as C-style strings. In that case, this function is @system.

See formatValue on how toString should be defined.

// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");

// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
       to!string(associativeArray) == `["1":2, "0":1]`);

// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");

// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);

auto c = to!(wchar[])(b);
assert(c == "abcx");

Strings can be converted to enum types. The enum member with the same name as the input string is returned. The comparison is case-sensitive.

A ConvException is thrown if the enum does not have the specified member.

import std.exception : assertThrown;

enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to
!
(alias) object.string = string
string
~ "]"
: (
(parameter) string path
path
.
(field) ulong string.length
length
?
(parameter) string path
path
~ "." ~
(foreach variable) const(char)[] name
name
.
string object.idup!(const(char))(const(char)[] a) pure nothrow @property @safe

Provide the .idup array property, which creates an immutable duplicate.

idup
:
(foreach variable) const(char)[] name
name
.
string object.idup!(const(char))(const(char)[] a) pure nothrow @property @safe

Provide the .idup array property, which creates an immutable duplicate.

idup
);
void property_tree_erased_subject.walk!(property_tree_erased_subject.Dyn)(ref property_tree_erased_subject.Dyn v, ref property_tree_erased_subject.Row[] rows, string path, string label, int depth, int maxDepth) @safe
walk
(
(foreach variable) property_tree_erased_subject.Dyn child
child
,
(parameter) property_tree_erased_subject.Row[] rows
rows
,
(local variable) const(string) p
p
,
(foreach variable) const(char)[] name
name
is null ? "[" ~
(foreach variable) ulong i
i
.
string std.conv.to!string.to!ulong(ulong __param_0) pure nothrow @safe

The to template converts a value from one type to another. The source type is deduced and the target type must be specified, for example the expression to`!int(42.0)` converts the number 42 from `double` to `int`. The conversion is "safe", i.e., it checks for overflow; to!int(4.2e10) would throw the ConvOverflowException exception. Overflow checks are only inserted when necessary, e.g., ``to!double(42) does not do any checking because any int fits in a double.

Conversions from string to numeric types differ from the C equivalents atoi() and atol() by checking for overflow and not allowing whitespace.

For conversion of strings to signed types, the grammar recognized is: Integer: Sign UnsignedInteger UnsignedInteger Sign: + -

For conversion to unsigned types, the grammar recognized is: UnsignedInteger: DecimalDigit DecimalDigit UnsignedInteger

Examples

Converting a value to its own type (useful mostly for generic code) simply returns its argument.

int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14

Converting among numeric types is a safe way to cast them around.

Conversions from floating-point types to integral types allow loss of precision (the fractional part of a floating-point number). The conversion is truncating towards zero, the same way a cast would truncate. (To round a floating point value when casting to an integral, use roundTo.)

import std.exception : assertThrown;

int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));

assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);

When converting strings to numeric types, note that D hexadecimal and binary literals are not handled. Neither the prefixes that indicate the base, nor the horizontal bar used to separate groups of digits are recognized. This also applies to the suffixes that indicate the type.

To work around this, you can specify a radix for conversions involving numbers.

auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);

Conversions from integral types to floating-point types always succeed, but might lose accuracy. The largest integers with a predecessor representable in floating-point format are 2^24-1 for float, 2^53-1 for double, and 2^64-1 for real (when real is 80-bit, e.g. on Intel machines).

// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);

Conversion from string types to char types enforces the input to consist of a single code point, and said code point must fit in the target type. Otherwise, ConvException is thrown.

import std.exception : assertThrown;

assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');

// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');

// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));

Converting an array to another array type works by converting each element in turn. Associative arrays can be converted to associative arrays as long as keys and values can in turn be converted.

import std.string : split;

int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);

Conversions operate transitively, meaning that they work on arrays and associative arrays of any complexity.

This conversion works because to`!short` applies to an `int`, to!wstring applies to a string, to`!string` applies to a `double`, and to!(double[]) applies to an int[]. The conversion might throw an exception because ``to!short might fail the range check.

int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);

Object-to-object conversions by dynamic casting throw exception when the source is non-null and the target is null.

import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));

Stringize conversion from all types is supported.

  • String to string conversion works for any two string types having (char, wchar, dchar) character widths and any combination of qualifiers (mutable, const, or immutable).

  • Converts array (other than strings) to string. Each element is converted by calling ``to!T.

  • Associative array to string conversion. Each element is converted by calling ``to!T.

  • Object to string conversion calls toString against the object or returns "null" if the object is null.

  • Struct to string conversion calls toString against the struct if it is defined.

  • For structs that do not define toString, the conversion to string produces the list of fields.

  • Enumerated types are converted to strings as their symbolic names.

  • Boolean values are converted to "true" or "false".

  • char, wchar, dchar to a string type.

  • Unsigned or signed integers to strings.

    special case

    : Convert integral value to string in radix radix. radix must be a value from 2 to 36. value is treated as a signed value only if radix is 10. The characters A through Z are used to represent values 10 through 36 and their case is determined by the letterCase parameter.

  • All floating point types to all string types.

  • Pointer to string conversions convert the pointer to a size_t value. If pointer is char*, treat it as C-style strings. In that case, this function is @system.

See formatValue on how toString should be defined.

// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");

// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
       to!string(associativeArray) == `["1":2, "0":1]`);

// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");

// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);

auto c = to!(wchar[])(b);
assert(c == "abcx");

Strings can be converted to enum types. The enum member with the same name as the input string is returned. The comparison is case-sensitive.

A ConvException is thrown if the enum does not have the specified member.

import std.exception : assertThrown;

enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to
!
(alias) object.string = string
string
~ "]"
:
(foreach variable) const(char)[] name
name
.
string object.idup!(const(char))(const(char)[] a) pure nothrow @property @safe

Provide the .idup array property, which creates an immutable duplicate.

idup
,
(parameter) int depth
depth
+ 1,
(parameter) int maxDepth
maxDepth
);
} } else static if (
(template instance) std.traits.isArray!(property_tree_erased_subject.Config)
isArray
!
(alias) T = property_tree_erased_subject.Config
T
&& !
(template instance) isSomeString!T
isSomeString
!
(alias) T = string[]
T
) // C18
{
(parameter) property_tree_erased_subject.Row[] rows
rows
~=
(struct) property_tree_erased_subject.Row
Row
(
(parameter) string path
path
,
(parameter) string label
label
,
(darray) string[]
T
.
(constant) string string[].stringof = "string[]"
stringof
,
string std.conv.text!(string, ulong, string)(string __param_0, ulong __param_1, string __param_2) pure nothrow @safe

Convenience functions for converting one or more arguments of any type into text (the three character widths).

text
("[",
(parameter) string[] v
v
.
(field) ulong string[].length
length
, " items]"),
(parameter) string[] v
v
.
(field) ulong string[].length
length
> 0);
if (
(parameter) int depth
depth
>=
(parameter) int maxDepth
maxDepth
) return;
foreach (
(parameter) ulong i
i
, ref
(parameter) string e
e
;
(parameter) string[] v
v
)
void property_tree_erased_subject.walk!string(ref string v, ref property_tree_erased_subject.Row[] rows, string path, string label, int depth, int maxDepth) pure nothrow @safe
walk
(
(local variable) string e
e
,
(parameter) property_tree_erased_subject.Row[] rows
rows
,
(parameter) string path
path
~ "[" ~
(local variable) ulong i
i
.
string std.conv.to!string.to!ulong(ulong __param_0) pure nothrow @safe

The to template converts a value from one type to another. The source type is deduced and the target type must be specified, for example the expression to`!int(42.0)` converts the number 42 from `double` to `int`. The conversion is "safe", i.e., it checks for overflow; to!int(4.2e10) would throw the ConvOverflowException exception. Overflow checks are only inserted when necessary, e.g., ``to!double(42) does not do any checking because any int fits in a double.

Conversions from string to numeric types differ from the C equivalents atoi() and atol() by checking for overflow and not allowing whitespace.

For conversion of strings to signed types, the grammar recognized is: Integer: Sign UnsignedInteger UnsignedInteger Sign: + -

For conversion to unsigned types, the grammar recognized is: UnsignedInteger: DecimalDigit DecimalDigit UnsignedInteger

Examples

Converting a value to its own type (useful mostly for generic code) simply returns its argument.

int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14

Converting among numeric types is a safe way to cast them around.

Conversions from floating-point types to integral types allow loss of precision (the fractional part of a floating-point number). The conversion is truncating towards zero, the same way a cast would truncate. (To round a floating point value when casting to an integral, use roundTo.)

import std.exception : assertThrown;

int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));

assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);

When converting strings to numeric types, note that D hexadecimal and binary literals are not handled. Neither the prefixes that indicate the base, nor the horizontal bar used to separate groups of digits are recognized. This also applies to the suffixes that indicate the type.

To work around this, you can specify a radix for conversions involving numbers.

auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);

Conversions from integral types to floating-point types always succeed, but might lose accuracy. The largest integers with a predecessor representable in floating-point format are 2^24-1 for float, 2^53-1 for double, and 2^64-1 for real (when real is 80-bit, e.g. on Intel machines).

// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);

Conversion from string types to char types enforces the input to consist of a single code point, and said code point must fit in the target type. Otherwise, ConvException is thrown.

import std.exception : assertThrown;

assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');

// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');

// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));

Converting an array to another array type works by converting each element in turn. Associative arrays can be converted to associative arrays as long as keys and values can in turn be converted.

import std.string : split;

int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);

Conversions operate transitively, meaning that they work on arrays and associative arrays of any complexity.

This conversion works because to`!short` applies to an `int`, to!wstring applies to a string, to`!string` applies to a `double`, and to!(double[]) applies to an int[]. The conversion might throw an exception because ``to!short might fail the range check.

int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);

Object-to-object conversions by dynamic casting throw exception when the source is non-null and the target is null.

import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));

Stringize conversion from all types is supported.

  • String to string conversion works for any two string types having (char, wchar, dchar) character widths and any combination of qualifiers (mutable, const, or immutable).

  • Converts array (other than strings) to string. Each element is converted by calling ``to!T.

  • Associative array to string conversion. Each element is converted by calling ``to!T.

  • Object to string conversion calls toString against the object or returns "null" if the object is null.

  • Struct to string conversion calls toString against the struct if it is defined.

  • For structs that do not define toString, the conversion to string produces the list of fields.

  • Enumerated types are converted to strings as their symbolic names.

  • Boolean values are converted to "true" or "false".

  • char, wchar, dchar to a string type.

  • Unsigned or signed integers to strings.

    special case

    : Convert integral value to string in radix radix. radix must be a value from 2 to 36. value is treated as a signed value only if radix is 10. The characters A through Z are used to represent values 10 through 36 and their case is determined by the letterCase parameter.

  • All floating point types to all string types.

  • Pointer to string conversions convert the pointer to a size_t value. If pointer is char*, treat it as C-style strings. In that case, this function is @system.

See formatValue on how toString should be defined.

// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");

// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
       to!string(associativeArray) == `["1":2, "0":1]`);

// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");

// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);

auto c = to!(wchar[])(b);
assert(c == "abcx");

Strings can be converted to enum types. The enum member with the same name as the input string is returned. The comparison is case-sensitive.

A ConvException is thrown if the enum does not have the specified member.

import std.exception : assertThrown;

enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to
!
(alias) object.string = string
string
~ "]",
"[" ~
(local variable) ulong i
i
.
string std.conv.to!string.to!ulong(ulong __param_0) pure nothrow @safe

The to template converts a value from one type to another. The source type is deduced and the target type must be specified, for example the expression to`!int(42.0)` converts the number 42 from `double` to `int`. The conversion is "safe", i.e., it checks for overflow; to!int(4.2e10) would throw the ConvOverflowException exception. Overflow checks are only inserted when necessary, e.g., ``to!double(42) does not do any checking because any int fits in a double.

Conversions from string to numeric types differ from the C equivalents atoi() and atol() by checking for overflow and not allowing whitespace.

For conversion of strings to signed types, the grammar recognized is: Integer: Sign UnsignedInteger UnsignedInteger Sign: + -

For conversion to unsigned types, the grammar recognized is: UnsignedInteger: DecimalDigit DecimalDigit UnsignedInteger

Examples

Converting a value to its own type (useful mostly for generic code) simply returns its argument.

int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14

Converting among numeric types is a safe way to cast them around.

Conversions from floating-point types to integral types allow loss of precision (the fractional part of a floating-point number). The conversion is truncating towards zero, the same way a cast would truncate. (To round a floating point value when casting to an integral, use roundTo.)

import std.exception : assertThrown;

int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));

assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);

When converting strings to numeric types, note that D hexadecimal and binary literals are not handled. Neither the prefixes that indicate the base, nor the horizontal bar used to separate groups of digits are recognized. This also applies to the suffixes that indicate the type.

To work around this, you can specify a radix for conversions involving numbers.

auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);

Conversions from integral types to floating-point types always succeed, but might lose accuracy. The largest integers with a predecessor representable in floating-point format are 2^24-1 for float, 2^53-1 for double, and 2^64-1 for real (when real is 80-bit, e.g. on Intel machines).

// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);

Conversion from string types to char types enforces the input to consist of a single code point, and said code point must fit in the target type. Otherwise, ConvException is thrown.

import std.exception : assertThrown;

assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');

// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');

// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));

Converting an array to another array type works by converting each element in turn. Associative arrays can be converted to associative arrays as long as keys and values can in turn be converted.

import std.string : split;

int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);

Conversions operate transitively, meaning that they work on arrays and associative arrays of any complexity.

This conversion works because to`!short` applies to an `int`, to!wstring applies to a string, to`!string` applies to a `double`, and to!(double[]) applies to an int[]. The conversion might throw an exception because ``to!short might fail the range check.

int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);

Object-to-object conversions by dynamic casting throw exception when the source is non-null and the target is null.

import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));

Stringize conversion from all types is supported.

  • String to string conversion works for any two string types having (char, wchar, dchar) character widths and any combination of qualifiers (mutable, const, or immutable).

  • Converts array (other than strings) to string. Each element is converted by calling ``to!T.

  • Associative array to string conversion. Each element is converted by calling ``to!T.

  • Object to string conversion calls toString against the object or returns "null" if the object is null.

  • Struct to string conversion calls toString against the struct if it is defined.

  • For structs that do not define toString, the conversion to string produces the list of fields.

  • Enumerated types are converted to strings as their symbolic names.

  • Boolean values are converted to "true" or "false".

  • char, wchar, dchar to a string type.

  • Unsigned or signed integers to strings.

    special case

    : Convert integral value to string in radix radix. radix must be a value from 2 to 36. value is treated as a signed value only if radix is 10. The characters A through Z are used to represent values 10 through 36 and their case is determined by the letterCase parameter.

  • All floating point types to all string types.

  • Pointer to string conversions convert the pointer to a size_t value. If pointer is char*, treat it as C-style strings. In that case, this function is @system.

See formatValue on how toString should be defined.

// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");

// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
       to!string(associativeArray) == `["1":2, "0":1]`);

// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");

// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);

auto c = to!(wchar[])(b);
assert(c == "abcx");

Strings can be converted to enum types. The enum member with the same name as the input string is returned. The comparison is case-sensitive.

A ConvException is thrown if the enum does not have the specified member.

import std.exception : assertThrown;

enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to
!
(alias) object.string = string
string
~ "]",
(parameter) int depth
depth
+ 1,
(parameter) int maxDepth
maxDepth
);
} else static if (
(template instance) std.traits.isAggregateType!(property_tree_erased_subject.Config)
isAggregateType
!
(alias) T = property_tree_erased_subject.Config
T
&& !
(template instance) std.traits.isSomeString!(property_tree_erased_subject.Config)
isSomeString
!
(alias) T = property_tree_erased_subject.Config
T
)
{
(parameter) property_tree_erased_subject.Row[] rows
rows
~=
(struct) property_tree_erased_subject.Row
Row
(
(parameter) string path
path
,
(parameter) string label
label
,
(struct) property_tree_erased_subject.Config
T
.
(constant) string property_tree_erased_subject.Config.stringof = "Config"
stringof
, "", true);
if (
(parameter) int depth
depth
>=
(parameter) int maxDepth
maxDepth
) return;
static foreach (name; __traits(allMembers, T)) {{ static if (__traits(compiles, typeof(__traits(getMember, T, name))) && !is(typeof(__traits(getMember, T, name)) == function))
void property_tree_erased_subject.walk!string(ref string v, ref property_tree_erased_subject.Row[] rows, string path, string label, int depth, int maxDepth) pure nothrow @safe
walk
(__traits(getMember, v, name),
(parameter) property_tree_erased_subject.Row[] rows
rows
,
(parameter) string path
path
.
(field) ulong string.length
length
?
(parameter) string path
path
~ "." ~ name :
(constant) string property_tree_erased_subject.walk!(property_tree_erased_subject.Config).name = "name"
name
,
(constant) string property_tree_erased_subject.walk!(property_tree_erased_subject.Config).name = "name"
name
,
(parameter) int depth
depth
+ 1,
(parameter) int maxDepth
maxDepth
);
}} } else
(parameter) property_tree_erased_subject.Row[] rows
rows
~=
(struct) property_tree_erased_subject.Row
Row
(
(parameter) string path
path
,
(parameter) string label
label
,
(ushort) ushort
T
.
(constant) string ushort.stringof = "ushort"
stringof
,
string std.conv.text!ushort(ushort __param_0) pure nothrow @safe

Convenience functions for converting one or more arguments of any type into text (the three character widths).

text
(
(parameter) ushort v
v
), false);
}
(struct) property_tree_erased_subject.Row
Row
[]
property_tree_erased_subject.Row[] property_tree_erased_subject.rowsOf!(property_tree_erased_subject.Config)(ref property_tree_erased_subject.Config v, int maxDepth = 8) @safe
rowsOf
(T)(ref
(alias) T = property_tree_erased_subject.Config
T
(parameter) property_tree_erased_subject.Config v
v
, int
(parameter) int maxDepth
maxDepth
= 8)
{
(struct) property_tree_erased_subject.Row
Row
[]
(local variable) property_tree_erased_subject.Row[] rows
rows
;
void property_tree_erased_subject.walk!(property_tree_erased_subject.Config)(ref property_tree_erased_subject.Config v, ref property_tree_erased_subject.Row[] rows, string path, string label, int depth, int maxDepth) @safe
walk
(
(parameter) property_tree_erased_subject.Config v
v
,
(local variable) property_tree_erased_subject.Row[] rows
rows
, "", "(root)", 0,
(parameter) int maxDepth
maxDepth
);
return
(local variable) property_tree_erased_subject.Row[] rows
rows
;
} // ── a MIXED subject (C17) ──────────────────────────────────────────────────── struct
(struct) property_tree_erased_subject.Server
Server
{
(alias) object.string = string
string
(field) string property_tree_erased_subject.Server.host
host
= "localhost"; ushort
(field) ushort property_tree_erased_subject.Server.port
port
= 8080; }
struct
(struct) property_tree_erased_subject.Config
Config
{
(alias) object.string = string
string
(field) string property_tree_erased_subject.Config.name
name
= "demo";
(struct) property_tree_erased_subject.Server
Server
(field) property_tree_erased_subject.Server property_tree_erased_subject.Config.server
server
;
(alias) object.string = string
string
[]
(field) string[] property_tree_erased_subject.Config.tags
tags
;
(struct) property_tree_erased_subject.Dyn
Dyn
(field) property_tree_erased_subject.Dyn property_tree_erased_subject.Config.extra
extra
; // ← the erased hole in an otherwise static type
} void
void D main() @safe
main
()
{ import
(package) std
std
.
(module) std.stdio
Category Symbols
File handles _popen File isFileHandle openNetwork stderr stdin stdout
Reading chunks lines readf readfln readln
Writing toFile write writef writefln writeln
Misc KeepTerminator LockType StdioException

Standard I/O functions that extend core.stdc.stdio. core.stdc.stdio is publically imported when importing std.stdio.

There are three layers of I/O:

  1. The lowest layer is the operating system layer. The two main schemes are Windows and Posix.

  2. C's stdio.h which unifies the two operating system schemes.

  3. std.stdio, this module, unifies the various stdio.h implementations into a high level package for D programs.

Source

std/stdio.d

@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Alex Rønne Petersen
stdio
:
(alias template) writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))

Equivalent to $(D writef(fmt, args, '\n')).

writefln
,
(alias template) writeln = std.stdio.writeln(T...)(T args)

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Params: args = the items to write to stdout

Throws: In case of an I/O error, throws an $(LREF StdioException). Example: Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main() { string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }

} ---

writeln
;
(struct) property_tree_erased_subject.Config
Config
(local variable) property_tree_erased_subject.Config c
c
;
(local variable) property_tree_erased_subject.Config c
c
.
(field) string[] property_tree_erased_subject.Config.tags
tags
= ["a", "b"];
(local variable) property_tree_erased_subject.Config c
c
.
(field) property_tree_erased_subject.Dyn property_tree_erased_subject.Config.extra
extra
=
(struct) property_tree_erased_subject.Dyn
Dyn
.
property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.obj(property_tree_erased_subject.Dyn.Pair[] v) @safe
obj
([
(struct) property_tree_erased_subject.Dyn
Dyn
.
(struct) property_tree_erased_subject.Dyn.Pair
Pair
("retries",
(struct) property_tree_erased_subject.Dyn
Dyn
.
property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.of(double v) @safe
of
(3.0)),
(struct) property_tree_erased_subject.Dyn
Dyn
.
(struct) property_tree_erased_subject.Dyn.Pair
Pair
("hosts",
(struct) property_tree_erased_subject.Dyn
Dyn
.
property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.arr(property_tree_erased_subject.Dyn[] v) @safe
arr
([
(struct) property_tree_erased_subject.Dyn
Dyn
.
property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.of(string v) @safe
of
("h1"),
(struct) property_tree_erased_subject.Dyn
Dyn
.
property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.of(string v) @safe
of
("h2")])),
(struct) property_tree_erased_subject.Dyn
Dyn
.
(struct) property_tree_erased_subject.Dyn.Pair
Pair
("tls",
(struct) property_tree_erased_subject.Dyn
Dyn
.
property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.obj(property_tree_erased_subject.Dyn.Pair[] v) @safe
obj
([
(struct) property_tree_erased_subject.Dyn
Dyn
.
(struct) property_tree_erased_subject.Dyn.Pair
Pair
("verify",
(struct) property_tree_erased_subject.Dyn
Dyn
.
property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.of(bool v) @safe
of
(true))])),
]);
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("C16/C17/C18 — one walk over a subject that is half static,");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("half type-erased. Nothing in the walk knows which is which.\n");
foreach (
(parameter) property_tree_erased_subject.Row r
r
;
property_tree_erased_subject.Row[] property_tree_erased_subject.rowsOf!(property_tree_erased_subject.Config)(ref property_tree_erased_subject.Config v, int maxDepth = 8) @safe
rowsOf
(
(local variable) property_tree_erased_subject.Config c
c
))
{ int
(local variable) int depth
depth
;
foreach (
(parameter) immutable(char) ch
ch
;
(local variable) property_tree_erased_subject.Row r
r
.
(field) string property_tree_erased_subject.Row.path
path
) if (
(local variable) immutable(char) ch
ch
== '.' ||
(local variable) immutable(char) ch
ch
== '[')
(local variable) int depth
depth
++;
void std.stdio.writefln!(char, int, string, string, string, string, string)(in char[] fmt, int __param_1, string __param_2, string __param_3, string __param_4, string __param_5, string __param_6) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("%*s%-10s %-12s %-22s %s",
(local variable) int depth
depth
* 2, "",
(local variable) property_tree_erased_subject.Row r
r
.
(field) string property_tree_erased_subject.Row.label
label
,
(local variable) property_tree_erased_subject.Row r
r
.
(field) bool property_tree_erased_subject.Row.expandable
expandable
? "▾" : " ",
(local variable) property_tree_erased_subject.Row r
r
.
(field) string property_tree_erased_subject.Row.type
type
,
(local variable) property_tree_erased_subject.Row r
r
.
(field) string property_tree_erased_subject.Row.value
value
);
}
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("\n paths across the seam are one syntax:");
foreach (
(parameter) string p
p
; ["server.port", "tags[1]", "extra.retries",
"extra.hosts[0]", "extra.tls.verify"])
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" %s",
(local variable) string p
p
);
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("\nC19 — the dynamic type states its own expandability, so the row");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(" model has no case for it:");
void std.stdio.writefln!(char, bool, bool)(in char[] fmt, bool __param_1, bool __param_2) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" Dyn(object).propExpandable = %s, Dyn(number) = %s",
(local variable) property_tree_erased_subject.Config c
c
.
(field) property_tree_erased_subject.Dyn property_tree_erased_subject.Config.extra
extra
.
bool property_tree_erased_subject.Dyn.propExpandable() const pure nothrow @nogc @safe

The rest of the capability: is this expandable, and how does it read?

propExpandable
,
(struct) property_tree_erased_subject.Dyn
Dyn
.
property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.of(double v) @safe
of
(1.0).
bool property_tree_erased_subject.Dyn.propExpandable() const pure nothrow @nogc @safe

The rest of the capability: is this expandable, and how does it read?

propExpandable
);
void std.stdio.writefln!(char, bool, bool)(in char[] fmt, bool __param_1, bool __param_2) @safe

Equivalent to writef(fmt, args, '\n').

writefln
(" hasPropChildren!Dyn = %s, hasPropChildren!Server = %s",
(template instance) property_tree_erased_subject.hasPropChildren!(property_tree_erased_subject.Dyn)
hasPropChildren
!
(struct) property_tree_erased_subject.Dyn
Dyn
,
(template instance) property_tree_erased_subject.hasPropChildren!(property_tree_erased_subject.Server)
hasPropChildren
!
(struct) property_tree_erased_subject.Server
Server
);
}