Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

Change Log: 2.088.0

previous version: 2.087.1 – next version: 2.088.1

Download D 2.088.0
released Sep 01, 2019

2.088.0 comes with 27 major changes and 58 fixed Bugzilla issues. A huge thanks goes to the 58 contributors who made 2.088.0 possible.

List of all bug fixes and enhancements in D 2.088.0.

Compiler changes

  1. D1 operator overloads have been deprecated.

    The following D1 operator overloads have been deprecated in favor of opUnary:

    • opNeg Replace with opUnary(string op)() if (op == "-")
    • opCom Replace with opUnary(string op)() if (op == "~")
    • opPostInc Replace with opUnary(string op)() if (op == "++")
    • opPostDec Replace with opUnary(string op)() if (op == "--")
    • opStar Replace with opUnary(string op)() if (op == "*")

    The following D1 operator overloads have been deprecated in favor of opBinary:

    • opAdd Replace with opBinary(string op)(...) if (op == "+")
    • opSub Replace with opBinary(string op)(...) if (op == "-")
    • opMul Replace with opBinary(string op)(...) if (op == "*")
    • opDiv Replace with opBinary(string op)(...) if (op == "/")
    • opMod Replace with opBinary(string op)(...) if (op == "%")
    • opAnd Replace with opBinary(string op)(...) if (op == "&")
    • opXor Replace with opBinary(string op)(...) if (op == "^")
    • opOr Replace with opBinary(string op)(...) if (op == "|")
    • opShl Replace with opBinary(string op)(...) if (op == "<<")
    • opShr Replace with opBinary(string op)(...) if (op == ">>")
    • opUShr Replace with opBinary(string op)(...) if (op == ">>>")
    • opCat Replace with opBinary(string op)(...) if (op == "~")
    • opIn Replace with opBinary(string op)(...) if (op == "in")

    The following D1 operator overloads have been deprecated in favor of opBinaryRight:

    • opAdd_r Replace with opBinaryRight(string op)(...) if (op == "+")
    • opSub_r Replace with opBinaryRight(string op)(...) if (op == "-")
    • opMul_r Replace with opBinaryRight(string op)(...) if (op == "*")
    • opDiv_r Replace with opBinaryRight(string op)(...) if (op == "/")
    • opMod_r Replace with opBinaryRight(string op)(...) if (op == "%")
    • opAnd_r Replace with opBinaryRight(string op)(...) if (op == "&")
    • opXor_r Replace with opBinaryRight(string op)(...) if (op == "^")
    • opOr_r Replace with opBinaryRight(string op)(...) if (op == "|")
    • opShl_r Replace with opBinaryRight(string op)(...) if (op == "<<")
    • opShr_r Replace with opBinaryRight(string op)(...) if (op == ">>")
    • opUShr_r Replace with opBinaryRight(string op)(...) if (op == ">>>")
    • opCat_r Replace with opBinaryRight(string op)(...) if (op == "~")
    • opIn_r Replace with opBinaryRight(string op)(...) if (op == "in")

    The following D1 operator overloads have been deprecated in favor of opOpAssign:

    • opAddAssign Replace with opOpAssign(string op)(...) if (op == "+")
    • opSubAssign Replace with opOpAssign(string op)(...) if (op == "-")
    • opMulAssign Replace with opOpAssign(string op)(...) if (op == "*")
    • opDivAssign Replace with opOpAssign(string op)(...) if (op == "/")
    • opModAssign Replace with opOpAssign(string op)(...) if (op == "%")
    • opAndAssign Replace with opOpAssign(string op)(...) if (op == "&")
    • opOrAssign Replace with opOpAssign(string op)(...) if (op == "|")
    • opXorAssign Replace with opOpAssign(string op)(...) if (op == "^")
    • opShlAssign Replace with opOpAssign(string op)(...) if (op == "<<")
    • opShrAssign Replace with opOpAssign(string op)(...) if (op == ">>")
    • opUShrAssign Replace with opOpAssign(string op)(...) if (op == ">>>")
    • opCatAssign Replace with opOpAssign(string op)(...) if (op == "~")

    Starting with this release, any D code that triggers a lowering to the D1 operator overloads will emit a deprecation warning.

    Example of deprecation warning:

    struct S
    {
        int opAdd(int i) { ... }
    }
    
    void main()
    {
        S s;
        int i;
        i = s + 1;  // Deprecation: `opAdd` is deprecated.  Use `opBinary` instead.
    }
    

    Example of corrective action:

    struct S
    {
        int opBinary(string op)(int i) if (op == "+") { ... }
    }
    
    void main()
    {
        S s;
        int i;
        i = s + 1;  // OK
    }
    
  2. Deprecate allowing a constructor declaration in a static block

    The language specification states that a static constructor is defined using the construction static this(). Defining a constructor inside a static block does not have any effect on the constructor. The following code does not affect the constructor in any way:

    static:
        this() {}
    
    static
    {
        this() {}
    }
    

    The compiler does not issue any warning/error on the above code samples and generates a normal constructor which is not ran before the main function. This leads to situations in which the compiler is not able to correctly indicate the problem:

    class A
    {
        static
        {
            this() {}
        }
    
        this() {}
    }
    
    void main()
    {
        new A();
    }
    

    This code will result in an error message indicating that there is a multiple definition of the constructor this() which is a misleading message.

    Beginning with this release, whenever a constructor is encountered in a static context an error message is emitted stating that the static keyword does not have any effect on the constructor. The solution is to declare the constructor outside the static block either as a normal constructor or a static one (static this()).

  3. deprecated now applies to alias this as well

    Before this release, deprecated on alias this was accepted by the parser but did not trigger a deprecation mesage on usage.

  4. Double initialization of immutable fields inside constructor is now obsolete

    Inside a constructor scope, assigning to aggregate declaration (class/struct) members is done by considering the first assignment as initialization and subsequent assignments as modifications of the initially constructed object. For const/immutable fields the initialization is accepted in the constructor, but subsequent modifications are not. Example:

    class A
    {
        int a;
        immutable int b;
        this(int a, int b)
        {
            this.a = a;
            this.b = b;
    
            this.a = 7; // OK, a is mutable
            this.b = 9; // Error: immutable field b initialized multiple times
        }
    }
    

    However, Bugzilla 18719 shows that this rule does not apply when inside a constructor scope there is a call to a different constructor:

    class A
    {
        immutable int a;
        this()
        {
            this(42);
            this.a = 5;  // second initialization of immutable field
        }
    
        this(int a)
        {
            this.a = a;
        }
    }
    

    The above code wrongfully compiled succesfully before this patch, accepting the double initialization of the immutable field a. Starting with this release, this.a = 5 will emit an error stating that a is initialized multiple times.

  5. add __traits(getLocation, symbol)

    Takes one argument which is a symbol. Returns a tuple(string, int, int) whose entries correspond to the filename, line number and column number where the argument was declared.

    To disambiguate between overloads, pass the result of getOverloads with the desired index, to getLocation:

    module m;
    int foo();
    int foo(int);
    enum loc = __traits(getLocation, __traits(getOverloads, m, "foo")[0]);
    
  6. Suppress the "read-modify-write" error if type is a struct or a class

    If a struct or class with shared type implements the opUnary or opOpAssign operator then it is possible to perform "read-modify-write" operations because the operator's implementation is supposed to perform atomic operations.

    The purpose of this modification is to allow the creation of wrappers (with structs or classes) to run atomic operations silently, for example:

    shared struct Atomic {
        int a;
    
        int opUnary(string s)() if (s == "++")
        {
            import core.atomic : atomicOp;
            return atomicOp!"+="(a, 1);
        }
    }
    
    Atomic atomicvar;
    atomicvar++; // Safe! Atomic struct implements opUnary
    
  7. Postblit and destructors are no longer called on members of anonymous unions.

    Due to a bug in dmd, members of anonymous unions inside struct declarations had their postblits/destructors called when an object of the containing struct type was copied/destroyed. With this release, the postblit/destructor is no longer called in such situations.

    Fixes: https://issues.dlang.org/show_bug.cgi?id=19122

Runtime changes

  1. core.atomic : msync has been removed

    It had been deprecated in 2.061 in favor of MemoryOrder.

  2. Added overloads for core.atomic.cas which don't discard their result.

    Existing core.atomic.cas functions discard the result, which make it impossible to implement certain operations. A new set of overloads was added which take ifThis by pointer and write the result back to the argument.

  3. Added core.atomic.atomicExchange.

    Added missing core.atomic.atomicExchange function to the atomic suite.

  4. Non-POSIX CLOCK enum members have been removed from core.sys.posix.time

    Namely CLOCK_MONOTONIC_RAW, CLOCK_MONOTONIC_COARSE (linux), CLOCK_MONOTONIC_PRECISE, CLOCK_MONOTONIC_FAST (FreeBSD, DragonflyBSD), and CLOCK_MONOTONIC_COARSE (CRuntime_Glibc). Those were deprecated in 2.067. They are available on their respective platform modules.

  5. The druntime option callStructDtorsDuringGC has been deprecated.

    Starting with this release utilizing the callStructDtorsDuringGC runtime option will result in a deprecation message printed to stderr. The option will be removed in a future release.

  6. core.sys.posix.dlfcn : dladdr, dlvsym, Dl_info have been removed

    They are linux extensions, not POSIX, and thus can be found in core.sys.linux.dlfcn. They had been deprecated since 2.063.

  7. core.exception: Remove onHiddenFuncError / HiddenFuncError

    Those have been deprecated since 2.068, and are related to a language feature that is long gone.

  8. core.exception : setAssertHandler has been removed

    It had been deprecated in 2.064 in favor of assertHandler.

  9. core.thread : Fiber.call(bool) has been removed

    This had been deprecated since 2.068 in favor of Fiber.call(Rethrow.[Yes|No]).

  10. Module core.sys.linux.sys.netinet.tcp has been removed

    This module had been deprecated since 2.077.0. core.sys.linux.netinet.tcp should be imported instead.

  11. core.runtime : Runtime.initialize, Runtime.terminate functions taking ExceptionHandler have been removed

    They were deprecated since 2.065 in favor of rt_init C functions, which allow to initialize the runtime from C code.

  12. Added core.stdcpp.string.

    Added core.stdcpp.string, which links against C++ std::basic_string

    Known issues:

    Currently, the GCC (libstdc++) implementation has a known issue with the modern __cxx11 ABI, because the C++ struct contains an interior pointer which is illegal in D, and incompatible with D move semantics. To use core.stdcpp.string on linux/GCC, you must use the old string ABI by supplying -D_GLIBCXX_USE_CXX11_ABI=0 to g++, and also -version=_GLIBCXX_USE_CXX98_ABI to your D compiler. Work to define D move constructors is ongoing and expected to resolve this issue when it arrives.

  13. Added core.stdcpp.vector.

    Added core.stdcpp.vector, which links against C++ std::vector

Library changes

  1. std.array.Appender and RefAppender: use .opSlice() instead of data()

    Previonsly, Appender.data() was used to extract a slice of the Appender's array. Now use the [] slice operator instead. The same goes for RefAppender.

    std.array.Appender std.array.RefAppender

  2. ErrnoException.errno is now nothrow pure @nogc @safe

    Before, it was just @system. As it turns out, all it does is return the value of an integer field, so it can have all these attributes.

  3. Nullable alias get this has been deprecated

    Nullable's feature of implicitly converting to its contained value has been marked deprecated.

    All sites where a Nullable!T is implicitly converted to T, potentially throwing an error at runtime, will now produce a deprecation warning or error with -de.

    To fix this, explicitly use .get to access the contained value of the Nullable.

    alias get this is the only implicit conversion in D that may throw an error. Since it is an implicit conversion, it can easily be used accidentally and lead to unexpected runtime errors. By explicitly invoking get, the developer acknowledges that the operation has a chance of error. Conversely, by not implicitly converting Nullable!T to T, the compiler gives the developer a chance to spot forgotten isNull checks.

    This feature will be removed after release 2.096.

  4. Added the std.file.getAvailableDiskSpace functionality.

    std.file.getAvailableDiskSpace receives as a parameter the path of a file or directory in the file system, and returns the available disk space on the mounted filesystem. If the given path is nonexistent, an exception is thrown.

    import std.file;
    ulong size = getAvailableDiskSpace(".");
    assert(size > 0);
    
    import std.file;
    assertThrown(getAvailableDiskSpace("NonExistentFile"));
    
  5. Allow std.json to overlook trailing comma

    The JSON grammar does not allow trailing commas, however they are accepted by many JSON parsers. std.json now ignores trailing commas as well. Use JSONOptions.strictParsing to disable this behavior.

    import std.json;
    import std.exception : assertThrown, assertNotThrown;
    
    // before
    assertThrown(parseJSON(`{ "a" : { } , }`));
    
    // after
    assertNotThrown(parseJSON(`{ "a" : { } , }`));
    

Installer changes

  1. Bundled libcurl is now built with DONT_USE_RECV_BEFORE_SEND_WORKAROUND

    The bundled libcurl is now build with DONT_USE_RECV_BEFORE_SEND_WORKAROUND. See #399 for details.

Dub changes

  1. Support for dub global settings file at the root package level

    Dub settings file can now also be added to project root folder and has the highest priority.


List of all bug fixes and enhancements in D 2.088.0:

DMD Compiler regressions

  1. Bugzilla 20021: static if doesn't evaluate opCast(T : bool)
  2. Bugzilla 20057: compiler hang on conflicting local and imported template
  3. Bugzilla 20136: opEquals not recognized for AA key

DMD Compiler bugs

  1. Bugzilla 1142: .stringof performs semantic analysis
  2. Bugzilla 7443: Better diagnostic on wrongly written static constructor
  3. Bugzilla 9884: Refused initialization of const array in the module static this()
  4. Bugzilla 15795: bogus "conflicts with" error depending on order of declaration
  5. Bugzilla 15818: Multiple function declarations without definition cause ambiguity overloading error
  6. Bugzilla 18719: Doubly-called constructor against member when using forwarding constructors
  7. Bugzilla 18729: dmd -run executes in different environment
  8. Bugzilla 19122: Postblits and destructors called on members of anonymous unions
  9. Bugzilla 19315: #line inside token string affect outside code
  10. Bugzilla 19534: Wrong error message "only one index allowed to index int"
  11. Bugzilla 19646: Initialization of globals not checked for @safe
  12. Bugzilla 19919: Incorrect initialization of union when first member isn't marked = void
  13. Bugzilla 19925: static opDispatch not considered in WithStatement
  14. Bugzilla 19931: Missing error message when defining postblit, rvalue constructor and copy constructor
  15. Bugzilla 19968: @safe code can create invalid bools resulting in memory corruption
  16. Bugzilla 20001: Error: a struct is not a valid initializer for a _error_
  17. Bugzilla 20033: alias this does not support deprecated attribute
  18. Bugzilla 20047: call of static nested function ignores purity
  19. Bugzilla 20050: pure function should be able to return function pointer to impure static nested function
  20. Bugzilla 20073: Wrong implicit conversion for return type
  21. Bugzilla 20074: header file generation doesn't include attributes with CallExp
  22. Bugzilla 20096: error message 'cannot goto into try block' is followed by seg fault
  23. Bugzilla 20100: Segfault with checkaction=context on struct comparison
  24. Bugzilla 20108: -dip1000 defeated by auto
  25. Bugzilla 20113: Cannot find source code for runtime library file 'object.d' when the path contains '~'

DMD Compiler enhancements

  1. Bugzilla 1252: Inline assembler could support BasicType properties
  2. Bugzilla 18665: Deprecate Undocumented Operator Overloads
  3. Bugzilla 19917: unions should require that all members are = void initialised
  4. Bugzilla 19969: Unhelpful error when attempting (incorrectly) to append to a string
  5. Bugzilla 20000: Casting to interfaces disallowed in @safe code
  6. Bugzilla 20024: "No property x for type Y" error not as helpful as it should be
  7. Bugzilla 20037: Imports in module info should be deduplicated
  8. Bugzilla 20053: add mixin types
  9. Bugzilla 20059: mismatched function return type inference should give location of inferred type

Phobos bugs

  1. Bugzilla 19823: std.algorithm.iteration.filter's popFront doesn't always pop the first element like it's supposed to
  2. Bugzilla 19980: File.byLine skips first line in some cases when used inside map!()
  3. Bugzilla 19986: Can't assign large const T to std.Variant.VariantN
  4. Bugzilla 19987: std.variantN wastes space
  5. Bugzilla 20064: format separator fails with leading zeros
  6. Bugzilla 20097: SysTime cannot be used with std.concurrency.send
  7. Bugzilla 20129: AA require with File values gives "Error: return expression expected" in object.d

Phobos enhancements

  1. Bugzilla 16487: Add function to obtain the available disk space
  2. Bugzilla 19834: File exception for [std.file.copy] on windows shows the target file rather than the source file
  3. Bugzilla 19979: std.regex should return null instead of zero-length slice for non-matched captures
  4. Bugzilla 19983: Add fast path using slice assignment to std.internal.cstring.tempCString
  5. Bugzilla 19994: Can't nest self-referential Algebraic types
  6. Bugzilla 20069: std.format digit grouping separator (aka thousands separator) needs to be revisited
  7. Bugzilla 20098: Improve result of printing std.regex compiled pattern

Druntime bugs

  1. Bugzilla 20066: Assertion on void[] does not compile with -checkaction=context
  2. Bugzilla 20088: void[] cast unusable in betterC due to new __ArrayCast template

Druntime enhancements

  1. Bugzilla 19976: Simplify std.internal.convert.toUbyte CTFE path for float and double
  2. Bugzilla 20104: core.atomic has no exchange function
  3. Bugzilla 20122: core.atomic.cas discards result on failure

dlang.org bugs

  1. Bugzilla 19402: specs for promotion rule of shift exp is wrong
  2. Bugzilla 19944: Some examples on std.file docs page raise FileException

Contributors to this release (58)

A huge thanks goes to all the awesome people who made this release possible.

previous version: 2.087.1 – next version: 2.088.1