D is much more "C++ done right" (and then some). C and Zig are very barebones, close-to-the-metal language. D has garbage collection, classes, templates, exceptions, built-in dynamic arrays and hash tables, and on and on and on. The "Features Overview" page makes me go cross-eyed [1].
Yes, you can turn many of these things off or ignore them and just use D as a better C, but the same could be said of C++ (for some definition of "better"). Or most languages, really, if you squint enough.
Yes, and people do use C++ as a better C to get OO and a stronger type system, at the cost of compilation times (and the usual C++ pitfalls).
I use D as better C. I use it as better C++ at times. Once ownership/borrowing [1] is stable, I'll use it as a better Rust too.
For close-to-the-metal code, I use D's inline assembler [2]. "To go any lower level than that, you'd need a miniature soldering iron and a very, very steady hand." (Andrei Alexandrescu)
A common misconception, probably because the majority of D users are C++ veterans. But D was never designed as a successor to C++.
"One of the earliest design decisions that Walter made about D was that it would be easy to use
with software written in C. Many widely-used libraries are implemented in C or have a C interface.
He wanted to provide an easy path for established software companies to adopt the D language. A
straightforward approach was to guarantee that users of D could immediately take advantage of
any C library their project required without the need to reimplement it in D." from "Origins of the D programming language" by W.Bright, A.Alexandrescu, M.Parker.
D has an optional conservative mark-sweep Boehm GC which only gets triggered when you attempt to allocate something on the heap. If you don't do that, it won't bother you. Finally, you can explicitly disable it.
People generally ignore or miss the fact that D really shines when it comes CTFE, reflection and metaprogramming.
But native code is native code, there isn't a magical layer underneath that would make Zig closer to the metal than D, unless perhaps the voluntary Undefined Behaviour zig is willing to take such as those for loops.
This is the first time I see such a comparison :) D is a systems programming language with an optional GC and in the league with C/C++/Rust. I would add Nim and Zig here as well.
Nim is in the GC category (and its documentation says you should use a refcounting GC rather than turning it off). Zig does not use GC.
Memory management is one of the more important aspects of systems programming so it is useful to be clear about what is the main strategy used by each language.
You can use packages that have been converted to not use the GC and all of the libraries you would be using in C or C++.
You still get the following language features, which is more than what C, C++ or Rust have to offer (though Rust is hot on D's trail).
Unrestricted use of compile-time features
Full metaprogramming facilities
Nested functions, nested structs, delegates and lambdas
Member functions, constructors, destructors, operating overloading, etc.
The full module system
Array slicing, and array bounds checking
RAII (yes, it can work without exceptions)
scope(exit)
Memory safety protections
Interfacing with C++
COM classes and C++ classes
assert failures are directed to the C runtime library
switch with strings
final switch
unittest
printf format validation