Change Log: 2.079.0
Download D 2.079.0
released Mar 01, 2018
Compiler changes
- Argument mismatch errors have been improved
- The deprecation period of using the result of comma expression has ended
- Function parameters with default values are now allowed after variadic template parameters
- The delete keyword has been deprecated.
- The deprecation period of the -dylib flag on OSX has ended. Use -shared
- Experimental @nogc Exception throwing with -dip1008
- A compiler trait used to detect if a function is marked with @disable has been added.
- Fix Issue 17630 - selective imports find symbols in private imports of other modules
- Fix issue 17899 - Allow delegates to be initialised at compile time
- Fix Issue 18053 - mangle long/ulong as int64_t/uint64_t
- Fix Issue 18219 - Private import inside struct leaks symbols when used as VarDeclaration types
- Fix issue 18361 - Ddoc ability to opt-out of automatic keyword highlighting in running text
- D ABI change on Win32 and OSX targets
- HexString literals are deprecated.
- Added the -i command line option to automatically include imports
- Added -Xi=<name> to include more fields in the JSON output
- Lambda comparison using __traits(isSame, ...)
- Windows: Visual C++ and the Windows SDK are no longer required to build 64-bit executables
- Using D with no/minimal/custom runtime implementation in a pay-as-you-go fashion
- macOS deployment target was increased to 10.9
- Deprecate the use of selectively imported private members
- .ptr on arrays can no longer be used in @safe code
Runtime changes
Library changes
- std.format with strings passed during compile-time has been optimized
- Changed std.conv.hexString to return an immutable string literal
- Nullable!C.nullify no longer calls .destroy when C is a class or interface
- std.algorithm.iteration.substitute was added
- divMod was added to std.bigint.
- getDigit Was Added To std.bigint
- std.exception.enforce can now be used as an eponymous template to create your own enforce function
- import std.experimental.all as a global convenience import
- Replace std.experimental.allocator.IAllocator with std.experimental.allocator.RCIAllocator
- Replace std.experimental.allocator.ISharedAllocator with std.experimental.allocator.RCISharedAllocator
- readText now checks BOMs
- fold is added to std.parallelism.TaskPool
- nullSink was added to std.range
- std.range.slide (a fixed-size sliding window range) was added
- std.string.strip now accepts a string of characters to be stripped
- isSomeString and isNarrowString are now false for enums
- toString Can Now Use Output Ranges
List of all bug fixes and enhancements in D 2.079.0.
Compiler changes
- Argument mismatch errors have been improved
dmd now shows which argument failed to match a parameter with an explanatory error message.
void fill(ref char[16] buf, char c); void main() { fill("1234567890123456", '*'); const char[16] s; fill(s, '*'); }
Output:
fillchar.d(5): Error: function fillchar.fill(ref char[16] buf, char c) is not callable using argument types (string, char) fillchar.d(5): cannot pass rvalue argument "1234567890123456" of type string to parameter ref char[16] buf fillchar.d(8): Error: function fillchar.fill(ref char[16] buf, char c) is not callable using argument types (const(char[16]), char) fillchar.d(8): cannot pass argument s of type const(char[16]) to parameter ref char[16] buf
Note: Currently this change doesn't apply when the function has overloads.
- The deprecation period of using the result of comma expression has ended
Comma expressions have proven to be a frequent source of confusion, and bugs. Using their result will now trigger an error message.
The comma operator (,) allows executing multiple expressions and discards the result of them except for the last which is returned.
int a = 1; int b = 2; bool ret = a == 2, b == 2; // true
It's also common to use the comma operator in for-loop increment statements to allow multiple expressions.
for (; !a.empty && !b.empty; a.popFront, b.popFront)
Hence, using the comma operator in for-loop increment statements is still allowed.
Corrective Action
If possible, split the comma operator in two statements. Otherwise use lambdas.
auto result = foo(), bar(); // split off in two statements foo(); auto result = bar(); // or use lambdas auto result = {foo(); return bar();}();
Rationale
The comma operator leads to unintended behavior (see below for a selection) Moreover it is not commonly used and it blocks the ability to implement tuples as a language feature using commas.
A selection of problems through the accidental use of the comma operator:
writeln( 6, mixin("7,8"), 9 ); // 6, 8, 9 struct Vec { this(T...)(T args) { ... } } // missing type name Vec v = (0, 0, 3); // Vec(3) int a = 0; int b = 2; if (a == 1, b == 2) { // will always be reached } void foo(int x, int y=0) {} foo((a, b)); // Oops, foo(b) is called synchronized (lockA, lockB) {} // multiple expressions aren't currently implemented, but it compiles due to the comma operator
- Function parameters with default values are now allowed after variadic template parameters
Function parameters with default values are now allowed after variadic template parameters and when IFTI is used, always take their default values. This allows using special tokens (eg __FILE__) after variadic parameters, which was previously impossible.
For example:
string log(T...)(T a, string file = __FILE__, int line = __LINE__) { return text(file, ":", line, " ", a); } assert(log(10, "abc") == text(__FILE__, ":", __LINE__, " 10abc"));
This should be preferred to the previous workaround, which causes a new template instantiation for every invocation:
string log(string file = __FILE__, int line = __LINE__, T...)(T a);
- The delete keyword has been deprecated.
See the Deprecated Features for more information.
Starting with this release, using the delete keyword will result in a deprecation warning.
As a replacement, users are encouraged to use destroy if feasible, or core.memory.__delete as a last resort.
- The deprecation period of the -dylib flag on OSX has ended. Use -shared
The deprecation period of the -dylib flag on OSX has ended.
dmd -dylib awesome_d_library.d
Use the -shared flag to generate a shared library:
dmd -shared awesome_d_library.d
- Experimental @nogc Exception throwing with -dip1008
DIP 1008 has been merged and it can be previewed under the experimental -dip1008 flag:
void main() @nogc { throw new Exception("I'm @nogc now"); }
rdmd -dip1008 app.d
- A compiler trait used to detect if a function is marked with @disable has been added.
Prior to this release is was impossible to filter out @disable functions without using __trait(compiles), which was less than ideal since false could be returned for other reasons.
Now, in metaprogramming code, @disable functions can be detected accurately, using __traits(isDisabled) and even in overload sets:
module runnable; struct Foo { import std.stdio; @disable static void foo() {__PRETTY_FUNCTION__.writeln;} static void foo(int v) {__PRETTY_FUNCTION__.writeln;} static void bar() {__PRETTY_FUNCTION__.writeln;} @disable static void bar(int v) {__PRETTY_FUNCTION__.writeln;} } void test(T)() { foreach (member; __traits(allMembers, T)) foreach (overload; __traits(getOverloads, T, member)) static if (!__traits(isDisabled, overload)) { static if (is(typeof(&overload) == void function())) overload(); else static if (is(typeof(&overload) == void function(int))) overload(42); } } void main(){test!Foo;}
prints:
void runnable.Foo.foo(int v) void runnable.Foo.bar()
- Fix Issue 17630 - selective imports find symbols in private imports of other modules
Selectively importing a symbol should work only if the symbol imported is defined or publicly imported in the imported module. Due to a compiler bug, selectively importing a symbol works even if the symbol is defined in a privately imported module in the imported module.
//a.d int bar; //b.d import a; //c.d import b : bar;
The above code will now result in a deprecation message which states that bar cannot be accessed since it is privately imported in b.
- Fix issue 17899 - Allow delegates to be initialised at compile time
delegates may now be initialised at module scope. This changes the effect of the fix for 13259 (turning the ICE that resulted into an error) making the follow legal:
void delegate() bar = (){};
The function pointer is set to the function of the delegate, the context pointer is set to null.
- Fix Issue 18053 - mangle long/ulong as int64_t/uint64_t
This is a breaking change (on OSX 64).
Due to the erratic implementation defined behavior of C++ name mangling, it was difficult to get D's long/ulong to portably match up with the corresponding C++ compiler.
By instead relying on how the corresponding C++ compiler mangled int64_t/uint64_t it makes the C++ side of the D<=>C++ interface much simpler.
For the current platforms dmd supports, only the OSX 64 bit mangling changes. In this case from 'm' to 'y'.
Note: int64_t and uint64_t are defined in stdint.h
- Fix Issue 18219 - Private import inside struct leaks symbols when used as VarDeclaration types
When implementing a struct which has a local private import the imported symbols are leaked if present in a VarDeclaration statement. For more information and examples see : https://issues.dlang.org/show_bug.cgi?id=18219
Symbols from the private import should not visible outside the struct scope. A deprecation is now issued when such cases are encountered
- Fix issue 18361 - Ddoc ability to opt-out of automatic keyword highlighting in running text
Currently, ddoc automatically highlights all occurrences of words in running text that coincide with the symbol or module being documented, or a parameter name of a function being documented. While convenient, it often caused unintended highlighting of normal words in text when module, function, or parameter identifiers coincide with normal words. This led to a proliferation of prefixing words with _ in order to suppress this behaviour.
Now a better solution has been implemented to completely opt-out of this feature via the DDOC_AUTO_PSYMBOL, DDOC_AUTO_KEYWORD, and DDOC_AUTO_PARAM macros, which are used for all such automatically-highlighted words in running text. Occurrences of module, function, or parameter names inside code blocks are not included. By default, these macros simply redirect to DDOC_PSYMBOL, DDOC_KEYWORD, and DDOC_PARAM, but the user can now redefine these macros so that they simply expand to the word itself without any highlighting:
DDOC_AUTO_PSYMBOL = $0 DDOC_AUTO_KEYWORD = $0 DDOC_AUTO_PARAM = $0
Furthermore, whenever a word is prefixed with _ to suppress automatic highlighting, it is now wrapped in the DDOC_AUTO_PSYMBOL_SUPPRESS macro. This is to provide users who wish to opt out of automatic highlighting an easy way to find all occurrences of these underscore prefixes so that they can be removed from the text. For example, they can redefine this macro to something highly-visible and easily searched for, such as:
DDOC_AUTO_PSYMBOL_SUPPRESS = FIXME_UNDERSCORE_PREFIX
and then search the generated documentation for the string FIXME_UNDERSCORE_PREFIX and delete the _ prefix from all corresponding parts of the documentation comment text.
- D ABI change on Win32 and OSX targets
The compiler has been updated to prefix all extern(D) symbols with an extra underscore where the platform expects one on all external symbols. This allows compiled code to work better with binutil programs, such as the ability to list symbols demangled inside a debugger.
This is an ABI breaking change and requires recompiling libraries.
- HexString literals are deprecated.
HexString literals are deprecated. Use std.conv.hexString instead.
- Added the -i command line option to automatically include imports
Added the command line option -i which causes the compiler to treat imported modules as if they were given on the command line. The option also accepts "module patterns" that include/exclude modules based on their name. For example, the following will include all modules whose names start with foo, except for those that start with foo.bar:
dmd -i=foo -i=-foo.bar
The option -i by itself is equivalent to:
dmd -i=-std -i=-core -i=-etc -i=-object
- Added -Xi=<name> to include more fields in the JSON output
Added -Xi=<name> to include more fields in the JSON output. Currently there are 4 fields that can be included: "compilerInfo", "buildInfo", "modules" and "semantics", i.e.
dmd -Xi=compilerInfo -Xi=buildInfo -Xi=semantics -Xi=modules
will generate a JSON file with the following:
{ "compilerInfo" : { "binary" : "<filename-of-compiler-binary>", "version" : "<compiler-version>", "supportsIncludeImports" : true, }, "buildInfo" : { "config" : "<config-filename>", "cwd" : "<cwd-during-build>", "importParths" : [ "<import-path1>", "<import-path2>", // ... ] }, "semantics" : { "modules" : [ { "name" : "<module-name>", "file" : "<module-filename>", "isRoot" : true|false }, // more module objects... ] }, "modules" : [ // an array of the syntax data for all the modules, // this is the same array that would be generated // for a JSON file with no -Xi=<field> options ] }
If JSON is generated without any -Xi= options then the old format is used. The old format is the same data that would appear in the new "modules" field.
Also note that the compiler can now be invoked with no source files as long as at least one JSON field is provided, i.e.
dmd -Xi=compilerInfo
This is an experimental command-line flag and will be stabilized in the next release.
- Lambda comparison using __traits(isSame, ...)
It is now possible to compare two lambda functions, under certain constraints, using __traits(isSame, lamda1, lambda2). In order to correctly compare two lambdas, the following conditions must be satisfied:
- the lambda function arguments must not have a template instantiation as an explicit argument type. Any other argument types (basic, user-defined, template) are supported.
- the lambda function body must contain a single expression (no return statement) which contains only numeric values, manifest constants, enum values and arguments. If the expression contains local variables, function calls or return statements, the function is considered uncomparable.
These limitations might be lifted in the next release version.
Whenever a lambda is considered uncomparable, the __traits(isSame, ...) expression in which it's used will return false, no matter what other lambda is used in the comparison.
- Windows: Visual C++ and the Windows SDK are no longer required to build 64-bit executables
The Windows installer now adds platform libraries built from the MinGW definitions and a wrapper library for the VC2010 shared C runtime. When building COFF object files with -m64 or -m32mscoff and no Visual Studio installation is detected or no platform libraries are found these will be used as replacements. If the Microsoft linker is not found, the LLVM linker LLD will be used.
- Using D with no/minimal/custom runtime implementation in a pay-as-you-go fashion
DMD has been further decoupled from the runtime so it is now easier and more convenient to use D without the runtime in a pay-as-you-go fashion. This will be of interest to users wishing to incrementally or partially port D to new platforms, users targeting bare-metal or resource constrained platforms, and users wishing to use D as a library from other languages without the runtime.
Prior to this release, if one attempted to compile a simple D application that made no use of any runtime features, the compiler would have emitted a number of errors about a missing object.d, a missing Error class, missing TypeInfo, and missing ModuleInfo, among others.
Starting with this release, one can now create a library for use from another language, requiring only the .d source file that implements that library, and an empty object.d file
Example 1
module object
module math; extern(C) int add(int a, int b) { return a + b; }
dmd -conf= -lib math.d size math.a text data bss dec hex filename 0 0 0 0 0 math.o (ex math.a) 20 0 0 20 14 math_1_129.o (ex math.a)
Also, starting with this release, one can now create very small executables with a minimal runtime implementation.
Example 2
DMD auto-generates a call to _d_run_main which, in turn, calls the user-defined main function. DMD automatically generates a call to g++ which links in the C runtime.
module object; private alias extern(C) int function(char[][] args) MainFunc; private extern (C) int _d_run_main(int argc, char** argv, MainFunc mainFunc) { return mainFunc(null); // assumes `void main()` for simplicity }
module main; void main() { }
dmd -conf= -defaultlib= -fPIC main.d object.d -of=main size main text data bss dec hex filename 1403 584 16 2003 7d3 main
Example 3
Manually generated call to main. No C runtime.
module object; extern(C) void __d_sys_exit(long arg1) { asm { mov RAX, 60; mov RDI, arg1; syscall; } } extern void main(); private extern(C) void _start() { main(); __d_sys_exit(0); }
module main; void main() { }
dmd -c -lib main.d object.d -of=main.o ld main.o -o main size main text data bss dec hex filename 56 0 0 56 38 main
Usage of more advanced D features (e.g. classes, exceptions, etc...) will require runtime implementation code, but they can be implemented in a pay-as-you-go fashion.
- macOS deployment target was increased to 10.9
The compiler has been updated to use 10.9 and link with libc++ on OSX. This is due the shared libstdc++ library from older versions of macOS having compatibility issues with the headers included in a modern XCode.
The minimum required version of running the compiler is now Mac OS X Mavericks (10.9).
- Deprecate the use of selectively imported private members
The specification states that a private member is visible only from within the same module. Prior to this release, due to a bug, private members were visible through selective imports from other modules, violating the specification. Beginning with this release, accessing private members from outside the module in which they are declared will result in a deprecation message.
- .ptr on arrays can no longer be used in @safe code
The deprecation period for using .ptr on arrays in @safe ended. The following now triggers an error instead of a deprecation:
@safe ubyte* oops(ubyte[] arr) { return arr.ptr; }
Use &arr[0] instead:
@safe ubyte* oops(ubyte[] arr) { return &arr[0]; }
Note that this only applies to SafeD - in @system code .ptr may still be used:
@system ubyte* oops(ubyte[] arr) { return arr.ptr; }
Runtime changes
- core.memory.__delete has been added
core.memory.__delete allows easy migration from the deprecated delete. __delete behaves exactly like delete:
bool dtorCalled; class B { int test; ~this() { dtorCalled = true; } } B b = new B(); B a = b; b.test = 10; __delete(b); assert(b is null); assert(dtorCalled); // but be careful, a still points to it assert(a !is null);
For example, on a Posix platform you can simply run:
sed "s/delete \(.*\);/__delete(\1);/" -i **/*.d
Users should prefer object.destroy` to explicitly finalize objects, and only resort to core.memory.__delete when object.destroy would not be a feasible option.
- The garbage collector is now lazily initialized on first use
The runtime now lazily initializes the GC on first use, thus allowing applications that do not use the GC to skip its initialization.
Library changes
- std.format with strings passed during compile-time has been optimized
Giving std.format.format a string as a template parameter allows the type correctness of the parameters to be checked at compile time:
import std.format : format; auto s1 = format!"%d"(4); // works fine auto s2 = format("%d"); // runtime exception auto s3 = format!"%d"(); // compile time error
Now, using this overload also allows std.format to make an educated guess at the length of the resulting string, reducing the total number of reallocations made to the output buffer.
import std.format : format; auto s1 = format!"%02d:%02d:%02d"(10, 30, 50); // known for certain to be 8 chars long auto s2 = format!"%s %d"("Error Code: ", 42); // Makes an educated guess
Longer format strings benefit the most from this change.
- Changed std.conv.hexString to return an immutable string literal
std.conv.hexString now returns an immutable string literal rather than an array of ubytes. This is more in keeping with the documentation that says it is a replacement for the deprecated x"deadbeef" string literal syntax.
The benefits of this change are:
- behavior consistency with the documentation
- the hexString template instantiations no longer appear in the generated object file
- the generated object file no longer contains references to TypeInfo and various druntime functions
- it is now compatible with -betterC mode
In some cases, code did rely on it being an array, and a cast will fix the issue:
// now an error: enum ubyte[8] input = hexString!"c3 fc 3d 7e fb ea dd aa";
// add cast to fix: enum ubyte[8] input = cast(ubyte[8]) hexString!"c3 fc 3d 7e fb ea dd aa";
- Nullable!C.nullify no longer calls .destroy when C is a class or interface
Previously, when .nullify is called on a Nullable!C where C is a class or interface, the underlying object is destructed immediately via the .destroy function. This led to bugs when there are still references to the object outside of the Nullable instance:
class C { int canary = 0xA71FE; ~this() { canary = 0x5050DEAD; } } auto c = new C; assert(c.canary == 0xA71FE); Nullable!C nc = nullable(c); nc.nullify; assert(c.canary == 0xA71FE); // This would fail
The .nullify method has been fixed so that it no longer calls .destroy on class or interface instances, and the above code will now work correctly.
- std.algorithm.iteration.substitute was added
std.algorithm.iteration.substitute yields a lazy range with all occurrences of the substitution patterns in r replaced with their substitution:
import std.algorithm.comparison : equal; import std.algorithm.iteration : substitute; // substitute single elements assert("do_it".substitute('_', ' ').equal("do it")); // substitute multiple, single elements assert("do_it".substitute('_', ' ', 'd', 'g', 'i', 't', 't', 'o') .equal("go to")); // substitute subranges assert("do_it".substitute("_", " ", "do", "done") .equal("done it")); // substitution works for any ElementType int[] x = [1, 2, 3]; auto y = x.substitute(1, 0.1); assert(y.equal([0.1, 2, 3])); static assert(is(typeof(y.front) == double));
If the substitution parameters are known at compile-time, the faster template overload can be used:
import std.algorithm.comparison : equal; import std.algorithm.iteration : substitute; // substitute subranges of a range assert("apple_tree".substitute!("apple", "banana", "tree", "shrub").equal("banana_shrub")); // substitute elements in a range assert("apple_tree".substitute!('a', 'b', 't', 'f').equal("bpple_free")); // substitute values assert('a'.substitute!('a', 'b', 't', 'f') == 'b');
- divMod was added to std.bigint.
std.bigint.divMod calculates both the quotient and the remainder in one go:
void divMod(const BigInt dividend, const BigInt divisor, out BigInt quotient, out BigInt remainder) pure nothrow { auto a = BigInt(123); auto b = BigInt(25); BigInt q, r; divMod(a, b, q, r); assert(q == 4); assert(r == 23); assert(q * b + r == a); }
- getDigit Was Added To std.bigint
std.bigint.getDigit gives the ulongs or uints that make up the underlying representation of the BigInt.
import std.bigint; auto a = BigInt("1000"); assert(a.getDigit(0) == 1000); auto b = BigInt("2_000_000_000_000_000_000_000_000_000"); assert(b.getDigit(0) == 4584946418820579328); assert(b.getDigit(1) == 108420217);
- std.exception.enforce can now be used as an eponymous template to create your own enforce function
std.exception.enforce now mirrors the behavior of std.exception.enforceEx and can be used as an eponymous template:
import std.conv : ConvException; alias convEnforce = enforce!ConvException; assertNotThrown(convEnforce(true)); assertThrown!ConvException(convEnforce(false, "blah"));
With this change, std.exception.enforce is a strict superset of std.exception.enforceEx, which will be deprecated in 2.079.
- import std.experimental.all as a global convenience import
std.experimental.all allows convenient use of all Phobos modules with one import:
import std.experimental.all; void main() { 10.iota.map!log.sum.writeln; }
For short scripts a lot of imports are often needed to get all the modules from the standard library. With this release it's possible to use import std.experimental.all for importing the entire standard library at once. This can be used for fast prototyping or REPLs:
import std.experimental.all; void main() { 6.iota .filter!(a => a % 2) // 0 2 4 .map!(a => a * 2) // 0 4 8 .tee!writeln .sum .writefln!"Sum: %d"; // 18 }
As before, symbol conflicts will only arise if a symbol with collisions is used. In this case, static imports or renamed imports can be used to uniquely select a specific symbol.
The baseline cost for import std.experimental.all is less than half a second (varying from system to system) and work is in progress to reduce this overhead even further.
- Replace std.experimental.allocator.IAllocator with std.experimental.allocator.RCIAllocator
Motivation:
Keep track of references to allocators so they don't escape, dangle, and cause undefined behavior.
From now on, RCIAllocator will be used instead of the old IAllocator interface. std.experimental.allocator.allocatorObject can be used to build a RCIAllocator out of a custom allocator.
import std.experimental.allocator.mallocator : Mallocator; RCIAllocator a = allocatorObject(Mallocator.instance); auto b = a.allocate(100); assert(b.length == 100); assert(a.deallocate(b));
- Replace std.experimental.allocator.ISharedAllocator with std.experimental.allocator.RCISharedAllocator
Motivation:
Keep track of references to allocators so they don't escape, dangle, and cause undefined behavior.
From now on, RCISharedAllocator will be used instead of the old ISharedAllocator interface. std.experimental.allocator.sharedAllocatorObject` can be used to build a RCISharedAllocator out of a custom allocator.
import std.experimental.allocator.building_blocks.free_list : SharedFreeList; import std.experimental.allocator.mallocator : Mallocator; shared SharedFreeList!(Mallocator, chooseAtRuntime, chooseAtRuntime) sharedFL; shared RCISharedAllocator sharedFLObj = sharedAllocatorObject(sharedFL); auto b = sharedFLObj.allocate(100); assert(b.length == 100); assert(sharedFLObj.deallocate(b));
- readText now checks BOMs
std.file.readText now checks for a BOM. If a BOM is present and it is for UTF-8, UTF-16, or UTF-32, std.file.readText verifies that it matches the requested string type and the endianness of the machine, and if there is a mismatch, a std.utf.UTFException is thrown without bothering to validate the string.
If there is no BOM, or if the BOM is not for UTF-8, UTF-16, or UTF-32, then the behavior is what it's always been, and UTF validation continues as per normal, so if the text isn't valid for the requested string type, a std.utf.UTFException will be thrown.
In addition, before the buffer is cast to the requested string type, the alignment is checked (e.g. 5 bytes don't fit cleanly in an array of wchar or dchar), and a std.utf.UTFException is now throw if the number of bytes does not align with the requested string type. Previously, the alignment was not checked before casting, so if there was an alignment mismatch, the cast would throw an Error, killing the program.
- fold is added to std.parallelism.TaskPool
std.parallelism.TaskPool.fold is functionally equivalent to TaskPool.reduce except the range parameter comes first and there is no need to use tuple for multiple seeds.
static int adder(int a, int b) { return a + b; } static int multiplier(int a, int b) { return a * b; } // Just the range auto x = taskPool.fold!adder([1, 2, 3, 4]); assert(x == 10); // The range and the seeds (0 and 1 below; also note multiple // functions in this example) auto y = taskPool.fold!(adder, multiplier)([1, 2, 3, 4], 0, 1); assert(y[0] == 10); assert(y[1] == 24); // The range, the seed (0), and the work unit size (20) auto z = taskPool.fold!adder([1, 2, 3, 4], 0, 20); assert(z == 10);
- nullSink was added to std.range
std.range.nullSink is a convenience wrapper for std.range.NullSink and creates an output range that discards the data it receives. It's the range analog of /dev/null.
import std.csv : csvNextToken; string line = "a,b,c"; // ignore the first column line.csvNextToken(nullSink, ',', '"'); line.popFront; // look at the second column Appender!string app; line.csvNextToken(app, ',', '"'); assert(app.data == "b");
- std.range.slide (a fixed-size sliding window range) was added
std.range.slide allows to iterate a range in sliding windows:
import std.array : array; import std.algorithm.comparison : equal; assert([0, 1, 2, 3].slide(2).equal!equal( [[0, 1], [1, 2], [2, 3]] )); assert(5.iota.slide(3).equal!equal( [[0, 1, 2], [1, 2, 3], [2, 3, 4]] )); assert(iota(7).slide(2, 2).equal!equal([[0, 1], [2, 3], [4, 5]])); assert(iota(12).slide(2, 4).equal!equal([[0, 1], [4, 5], [8, 9]])); // set a custom stepsize (default 1) assert(6.iota.slide(1, 2).equal!equal( [[0], [2], [4]] )); assert(6.iota.slide(2, 4).equal!equal( [[0, 1], [4, 5]] )); // allow slide with less elements than the window size assert(3.iota.slide!(No.withPartial)(4).empty); assert(3.iota.slide!(Yes.withPartial)(4).equal!equal( [[0, 1, 2]] ));
- std.string.strip now accepts a string of characters to be stripped
New overload functions of std.string.strip, std.string.stripLeft and std.string.stripRight accepts a string of characters to be stripped instead of stripping only whitespace.
import std.string: stripLeft, stripRight, strip; assert(stripLeft("www.dlang.org", "w.") == "dlang.org"); assert(stripRight("dlang.org/", "/") == "dlang.org"); assert(strip("www.dlang.org/", "w./") == "dlang.org");
- isSomeString and isNarrowString are now false for enums
Previously, enums whose base type was a string type were true for std.traits.isSomeString and std.traits.isNarrowString. Occasionally, this was useful, but in general, it was a source of bugs, because code that works with strings does not necessarily work with enums whose base type is a string, making it easy to write code where an enum would pass the template constraint and then the template would fail to compile. For instance, enums of base type string are false for std.range.primitives.isInputRange. As such, it really doesn't make sense for std.traits.isSomeString and std.traits.isNarrowString to be true for enums.
For some code, this will be a breaking change, but most code will either be unaffected, or it will then fail with enums at the template constraint instead of inside the function. So, the risk of code breakage is minimal but does exist. Other code will now be able to remove stuff like !is(T == enum) from its template constraints, since that is now part of std.traits.isSomeString and std.traits.isNarrowString, but it will continue to compile with the now unnecessary check for enums.
Code that uses std.traits.isSomeString or std.traits.isNarrowString in a template constraint and has no other conditions which would prevent enums from passing the constraint but then would fail to compile inside the template if an enum were passed to it will now fail to compile at the template constraint instead of inside the template. So, such code is fixed rather than broken.
The rare code that does break because of these changes is code that uses std.traits.isSomeString or std.traits.isNarrowString in a template constraint or static if and does not use other conditions to prevent enums from passing and actually has code in the template which compiles with both strings and enums with a base type of string. Such code will need to be changed to use std.traits.OriginalType, std.conv.asOriginalType, or std.traits.StringTypeOf instead. e.g. for enums to pass the constraint, instead of
auto foo(S)(S str) if (isSomeString!S) { ... }
the code would be
auto foo(S)(S str) if (isSomeString!(OriginalType!S)) { ... }
As a rule of thumb, generic code should either disallow implicit conversions and force the caller to do the conversion explicitly (which generally is the least error-prone approach), or it should force the conversion to the desired type before the parameter is used in the function so that the function is definitely operating on the desired type and not just on one that implicitly converts to it and thus will work regardless of whether the argument was the exact type or implicitly converted to it.
However, great care should be taken if the implicit conversion will result in slicing the parameter or otherwise referring to its address, since that makes it very easy for a reference to local memory to escape the function, whereas if the conversion is done at the call site, then the slicing is done at the call site, so the dynamic array is still valid when the function returns. Fortunately, enums with a base type of string do not have that problem, but other types which implicitly convert to dynamic arrays (such as static arrays) do have that problem, which is a big reason why it's generally recommended to not have generic functions accept types based on implicit conversions.
It is recommended that if a function is supposed to accept both strings and types which implicitly convert to a string type, then it should explicitly accept dynamic arrays but be templated on the element type. e.g.
auto foo(C)(C[] str) if (isSomeChar!C) { ... }
That way, any implicit conversions are done at the call site and do not introduce @safety problems inside the function. It also tends to result in template constraints which are shorter and more easily understood.
- toString Can Now Use Output Ranges
The standard library has been modified to recognize and use toString overloads that accept output ranges when such overloads exist.
import std.range.primitives; import std.stdio; struct MyType { void toString(W)(ref W writer) if (isOutputRange!(W, char)) { put(writer, "Custom toString"); } } auto t = MyType(); writeln(t); // writes "Custom toString"
This has several benefits for the user. First, this design is much friendlier to inlining than the toString(scope void delegate(const(char)[]) sink) method of toString. Second, this cuts down on memory usage, as characters are placed right into the output buffers of functions like std.format.format. Third, because toString is now a template, can be marked @safe via inference much more often.
All previous forms of toString will continue to work.
List of all bug fixes and enhancements in D 2.079.0:
DMD Compiler regressions
- Bugzilla 17605: [REG2.066.0] __traits(compiles, closure) adds link-time reference to _d_allocmemory
- Bugzilla 17970: shared struct destructor doesn't compile anymore
- Bugzilla 18030: Segmentation fault with __traits(getProtection) on template function.
- Bugzilla 18093: [Reg 2.071] MSCOFF: dmd crashes when overriding a C++ method in a mixin template
- Bugzilla 18097: [REG2.077] Unittest function is undefined identifier
- Bugzilla 18296: [Reg2.078.1] invalid code with coverage and copy construction
- Bugzilla 18322: void fun(string file=__FILE_FULL_PATH__)() returns relative path (pointing to nowhere)
- Bugzilla 18430: isSame is wrong for non global lambdas
- Bugzilla 18469: [REG 2.079-b1] Segfault when trying to get type of __dtor.opCall
- Bugzilla 18480: [Reg 2.079] dmd hangs with self-alias declaration
DMD Compiler bugs
- Bugzilla 8207: OS X: Should extern(D) symbols include another underscore?
- Bugzilla 8687: Variadic templates do not work properly with default arguments
- Bugzilla 9433: Deprecate delete
- Bugzilla 12511: static overloaded function is not accessible
- Bugzilla 12901: Assignments to outside members in in/out contracts shouldn't be allowed
- Bugzilla 14147: Compiler crash on identical functions in a single module
- Bugzilla 14907: DMD crash when using template name as a default value of template's typed argument
- Bugzilla 15777: Premature expansion of overload set in tuples
- Bugzilla 16042: Identifier on template arguments should consider eponymous member lookup
- Bugzilla 17437: Incorrect range check when implicitly converting integer literals to float/double
- Bugzilla 17570: Misleading error message illegal conditional function definition
- Bugzilla 17625: Confusing error message for private functions in different modules
- Bugzilla 17630: selective imports find symbols in private imports of other modules
- Bugzilla 17663: header generation (-H) is broken with public override of private default
- Bugzilla 18014: DMD test suite fails to link on Linux distros where PIC/PIE is enforced
- Bugzilla 18057: [ICE] Segmentation fault (stack overflow) in Expression::ctfeInterpret()
- Bugzilla 18083: -w doesn't work for the ddoc build
- Bugzilla 18143: in/out contracts should be implicitly 'this' const
- Bugzilla 18190: [asan] heap-buffer-overflow in Module.load.checkModFileAlias
- Bugzilla 18212: Usage of cfloat,cdouble,cfloat,ifloat,idouble,ireal shouldn't trigger an error in deprecated code
- Bugzilla 18218: __traits(isDeprecated, creal) should return true
- Bugzilla 18219: Private import inside struct leaks symbols when used as VarDeclaration types
- Bugzilla 18225: Wrong condition in VRP
- Bugzilla 18232: Union methods fail to initialize local variables to .init
- Bugzilla 18243: selective import + overload = private visibility
- Bugzilla 18261: Linkage information isn't part of the json output
- Bugzilla 18312: string concatenation with -betterC fails with linker errors
- Bugzilla 18335: The D_ObjectiveC version identifier is not printed in verbose mode
- Bugzilla 18364: header file generation doesn't print the package name in package(XXX)
- Bugzilla 18367: dmd should not segfault on -X with libraries, but no source files
- Bugzilla 18429: alias this enum causes segmentation fault
- Bugzilla 18468: cannot use synchronized {} in @safe code
DMD Compiler enhancements
- Bugzilla 6549: Implement contracts without implementation.
- Bugzilla 11529: Unclear error message when rvalue is passed as `ref'
- Bugzilla 11714: Improve error message for wrongly initialized thread-local class instances
- Bugzilla 13855: Allow multiple selective imports from different modules in a single import statement
- Bugzilla 16492: support @nogc in debug{} blocks
- Bugzilla 17899: Cannot initialise contextless delegate at compile time
- Bugzilla 18053: Use stdint.h mangling for int64_t/uint64_t when mangling D long/ulong
- Bugzilla 18149: Add a compiler trait to detect if a function is @disable
- Bugzilla 18273: Better C: wrong exit code from main()
- Bugzilla 18361: Ddoc: support ability to opt out of automatic keyword highlighting in text
- Bugzilla 18427: Symbol FOO is not visible because it is privately imported => compiler should show how to import it
Phobos regressions
- Bugzilla 18114: [Reg 2.078] regex performance regression
- Bugzilla 18316: std.net.curl.SMTP.mailTo fails to compile
Phobos bugs
- Bugzilla 7054: format() aligns using code units instead of graphemes
- Bugzilla 10879: std.variant Variant/Algebraic: Can't store static arrays > 32(/16) bytes
- Bugzilla 15157: std.experimental.allocator.building_blocks docs
- Bugzilla 15391: Problems loading libcurl.so and running datetime unittest on NixOS package build
- Bugzilla 17832: std.random.choice cannot be used with other random generators
- Bugzilla 18092: Can't combine take and takeExactly
- Bugzilla 18124: std.regex.RegexMatch's front property is under-documented
- Bugzilla 18153: deprecate public symbols ByLine, ByRecord, ByChunk
- Bugzilla 18224: BigInt modulo uint must return long.
- Bugzilla 18229: Misleading documentation of std.process.environment.get
- Bugzilla 18259: allocatorObject's CAllocatorImpl should store the passed allocator within
- Bugzilla 18278: writef documentation 404 error
- Bugzilla 18285: std.algorithm.comparison.cmp for strings with custom predicate compares lengths wrong
- Bugzilla 18286: std.algorithm.comparison.cmp for string with custom predicate fails if distinct chars can compare equal
- Bugzilla 18288: std.algorithm.comparison.cmp for wide strings should be @safe
- Bugzilla 18299: std.datetime.date.cmpTimeUnits does not throw a DateTimeException
- Bugzilla 18328: algorithm.startsWith can compare narrow string lengths in more circumstances
- Bugzilla 18349: std/math.d(543,33): Deprecation: integral promotion not done for -x
- Bugzilla 18384: std.net.isemail is slow to import due to regex
- Bugzilla 18397: Poor implementation of std.conv.hexString results in unintended bloat
- Bugzilla 18434: BigInt gcd asserts when one argument is zero.
- Bugzilla 18492: DLang STL links are broken
Phobos enhancements
- Bugzilla 5489: std.typecons tuples dynamically iterable
- Bugzilla 10828: datetime toString functions should accept sink
- Bugzilla 11084: std.algorithm.scan
- Bugzilla 11555: std.algorithm.reverse should return the just-reversed range
- Bugzilla 11747: Better error message with @disabled toString
- Bugzilla 13632: Second argument for std.string.strip
- Bugzilla 14767: Support CTFE of BigInt under x86
- Bugzilla 15949: Improve readtext handling of byte order mark (BOM)
- Bugzilla 17249: Make BigInt data visible (not modifiable!)
- Bugzilla 17440: Nullable.nullify() resets referenced object
- Bugzilla 18086: BigInt DivMod
- Bugzilla 18096: Add fold() to std.parallelism
- Bugzilla 18116: to!wchar([string, dstring]), and to!char([wstring, dstring]) don't compile
- Bugzilla 18152: std.format.formattedRead should work with rvalues.
- Bugzilla 18186: std.array.replaceSlice should be usable in @safe
- Bugzilla 18214: TemplateOf should return void for non-templated symbols
- Bugzilla 18217: Don't repeatedly call unpredictableSeed to initialize rndGen
- Bugzilla 18230: multiwayUnion sets wrong pred lambdas
- Bugzilla 18239: std.experimental.allocator fillWithMemcpy could use memset when T.sizeof==1
- Bugzilla 18280: std.algorithm.comparison.cmp for non-strings should call opCmp only once per item pair
- Bugzilla 18329: std.algorithm.startsWith & endsWith can sometimes statically determine decoding unnecessary
Druntime regressions
- Bugzilla 15482: new uuid.d forbids to link statically with other libraries
Druntime bugs
- Bugzilla 18240: core.stdc.wchar_ wmemset, etc. should be pure
- Bugzilla 18247: core.stdc.math functions that never set errno should be pure
- Bugzilla 18279: rt.util.utf does not properly reserve buffer in toUTF16/toUTF16z
- Bugzilla 18300: core.demangle demangling of really long symbol fails
- Bugzilla 18409: DScanner SEGFAULTS on CircleCI
- Bugzilla 18531: core.exception.RangeError@src/core/demangle.d(216): Range violation
dlang.org bugs
- Bugzilla 13844: core.stdc.config isn't listed in the docs
- Bugzilla 14475: man page is outdated
- Bugzilla 16490: Usage of attributes in inline asm blocks is not documented
- Bugzilla 18306: No compliation errors shown when running modified examples
- Bugzilla 18319: std.exception: enforce example does not compile
- Bugzilla 18341: Documentation for std.array.split is confusing/incorrect
- Bugzilla 18355: [Areas of D usage]
dlang.org enhancements
- Bugzilla 17998: Document Options for install.sh
- Bugzilla 18202: Show TOC overview in the dlang specification pages
- Bugzilla 18337: https://dlang.org/spec/operatoroverloading.html missing opIn/opIn_r
- Bugzilla 18379: [404 Not Found] Foundation Donate page not found
- Bugzilla 18383: Front page blog section is only partially filled.
Tools bugs
- Bugzilla 18208: demangle RangeError@src/core/demangle.d(230)
Installer bugs
- Bugzilla 15131: curl.lib is not available in 32 bit mscoff format
- Bugzilla 18510: [Beta 2.079] lld-link.exe fails to open obj file in subpath
Contributors to this release (78)
A huge thanks goes to all the awesome people who made this release possible.
- acehreli
- aG0aep6G
- aldacron
- Alexandru Jercaianu
- Ali Akhtarzada
- Ali Çehreli
- Andrei Alexandrescu
- Andrey Penechko
- Andy Smith
- Aravinda VK
- Arun Chandrasekaran
- Atila Neves
- Basile Burg
- Bastiaan Veelo
- BBasile
- Brad Roberts
- carblue
- Daniel Kozak
- Diederik de Groot
- dmdw64
- Dragos Carp
- Duncan Paterson
- Eduard Staniloiu
- Elias Batek
- H. S. Teoh
- Héctor Barreras Almarcha [Dechcaudron]
- Iain Buclaw
- Jack Stouffer
- Jacob Carlborg
- jacob-carlborg
- jercaianu
- jmh530
- Joakim Noah
- Johan Engelen
- Johannes Pfau
- Jonathan M Davis
- Jonathan Marler
- Joseph Rushton Wakeling
- Kai Nacke
- kinke
- Lance Bachmeier
- Lucia Mcojocaru
- Luís Marques
- Manuel Maier
- Markus F.X.J. Oberhumer
- Martin Nowak
- Mathias Baumann
- Mathis Beer
- MetaLang
- Michael Parker
- Mike Franklin
- Mike Parker
- Nathan Sashihara
- Nicholas Lindsay Wilson
- Nicholas Wilson
- Nick Treleaven
- Oleg Nykytenko
- Patrick Schlüter
- Paul Backus
- Petar Kirov
- Pradeep Gowda
- Radu Racariu
- Rainer Schuetze
- Razvan Nitu
- Sebastian Wilzbach
- shoo
- Simen Kjærås
- skl131313
- Stanislav Blinov
- Stefan Koch
- Steven Schveighoffer
- Thomas Mader
- Timothee Cour
- Tomáš Chaloupka
- Vladimir Panteleev
- Walter Bright
- Yannick Koechlin
- Yuxuan Shui