You only get one chance to make a first impression.

D failed with both first and second impression when they abandoned D1 and replaced it with D2. I know of few large projects that couldn’t be migrated cleanly enough to D2 at the time (D2 was plagued with bugs and big changes) so they stuck with D1 until they rewrote whole things in different languages. This is not the way you want to leave impression of stable, backward compatible language that offers safety and future. Source

I used D for months while writing Drill: https://github.com/yatima1460/drill/tree/D

After trying all programming languages, even the most obscure ones like Haxe (Papers Please is the only famous product made with it), I want to start the review of the D programming language using an analogy.

1. big.LITTLE

As you can imagine designing a CPU that is both powerful and battery-saving is VERY HARD, so ARM thought of a nice idea, instead of continuing the mobile market with just one CPU type they splitted their design in two completely opposite ways:

  • the big CPU is an ARM CPU that is designed to be super performant and doesn’t care about battery

  • the LITTLE CPU is a CPU that is designed to be super battery saver and weak

You will find new modern phones with like 6xLITTLE+2xbig or like 4xLITTLE and 4xbig, the difference with a phone with just 8xnormal cores is astonishing, as an example I got double the benchmark points in a test with a 8xnormal cores phone VS a 6xLITTLE+2xbig phone

So it’s very easy to design a CPU that only does one thing nearly perfectly, and I think this is a good analogy with D, C and C++ are very good only at performance and trust the programmer, C# and Java are very good only at memory safety; so we have a situation with “very” low level languages VS very high level languages.

D tries to do both and stays in the middle, not that it’s impossible, but this increases the price of maintenance a lot and scalability of the project.

D is like the bard in D&D: jack of all trades, master of none

2. Focus

It wants to be best at everything, but doesn’t have the money/support to do so. Source

The main problem of D is focus, the project tries to do so everything at once that sometimes they completely lose attachment with reality and forget even the most basic things, like Linus Torvalds said:

I’m perfectly happy with all the people who are walking around and just staring at the clouds and looking at the stars and saying, “I want to go there.” But I’m looking at the ground, and I want to fix the pothole that’s right in front of me before I fall in. This is the kind of person I am. - Linus Torvalds Source

I was pretty shocked to find that the D standard library doesn’t have a way to print and format dates and you need to rely to an external one, but at the same time it has the most advanced methods of parallelism and sorting.

As said before their main problem is focus, the D standard library is probably one of the biggest standard libraries out there and tries to cover all the possible usages, but at the same time they forget even the most basic things.

3. Minesweeper

3.1 Memory-safety? Yes, Productive? No

After some months programming only in D if you try to use D for everything you will stumble upon something interesting: SEGFAULTS with pure D code.

How is this even possible you may ask?

Isn’t D memory-safe if a developer uses @safe?

Well yes, but actually no

void function() @safe
{
    Object o

    // illegal with @safe, compiler will complain, nice
    auto ptr = &o;
}
void function() @safe
{
    Object o = null;

    /+
        Not illegal with @safe
        SEGFAULT here
     +/
    o.method();
}

Look how ugly this code is, @safe protects you against illegal memory writing but doesn’t help with productivity AT ALL.

Yes, technically speaking D is memory-safe, it will never corrupt memory inside a block of code marked with @safe, the problem is that you will NOT get a NullPointerException@LINE or similar but in the average scenario it will just crash and burn with GDB not always being able to catch where the NULL dereferencing happened.

Essentially what it comes down to is the fact that because the OS already detects null pointer dereferences for you (hence the segfault or access violation that you get when it occurs), Walter considers it unnecessary. If you want more details, look at the resulting core dump in a debugger or run the program in a debugger to begin with. Now, that obviously doesn’t always work, which is part of why many folks argue in favor of adding additional checks, but that’s Walter’s position. Source

So yes, it’s pretty stupid that after all those years Walter Bright still doesn’t want to add NULL checking.

It defeats all the productivity of D; having a NullPointerException when a reading happens at memory location 0 is SUPER HELPFUL, you may know that if you ever used Java or C#.

3.2 A real example of not checking for NULL destroying productivity

In D you will have Delegates and Functions, Delegates are just method pointers/closures, Functions are just function pointers.

The interesting thing is that you can convert one to the other by binding/unbinding an object.

The problem?

If you convert a Delegate to a Function and then call the Function without rebinding it to an object, D will crash really hard.

Why?

Because Delegates are implemented as structs with a pointer to the object and a pointer to the method, and the internal pointer to the object will become NULL and this will crash D because NULL checking is the only memory-safetyness that is not implemented.

This is an edge case but shows why not having NULL checking in D really hinders the producitivity of the language; all the time I spent with a debugger was caused just because Walter didn’t want to add NULL checking.

The basic problem I am noticing is that when programming in D you don’t know how to behave, should you check every pointer like in C? Or nothing like in C# because the interpreter will actually tell you when you try to read a NULL pointer?

You know that programming in C is like walking on a minefield, but D feels like walking on a minefield but with only 1 mine called NULL.

3.2 Why void**????

The only time I had to fire the debugger that wasn’t caused by D not checking for NULLs was when by mistake I created a void** pointer.

I did a &variable on a void* instead of just passing the void* thinking it wasn’t already a pointer to the variable I needed.

GCC would have warned you saying you are passing a wrong pointer type and it may decay into another..

But no, not the D compiler, the D compiler by default actually considers errors unused code but doesn’t warn you when a pointer decays into another…

I proposed the idea to add a warning to it or actually to make void** optional with a flag.

Seriously who needs void** in real life situations? It’s better to have void multi-pointers as an opt-in feature in a language like D that has heavy use of @safe.

4. The mess with @nogc

The @nogc keyword is pretty cool, it allows you to mark a region of code GC-free and it’s checked by the compiler if you try to use the garbage collector.

The problem?

The majority of the standard library still uses the GC so you will end up with using @nogc in one or two functions…

5. The mess with pure

D offers the keyword pure, so you can mark a function pure and it will be checked by the compiler if it tries to read and write global variables, pretty cool and I would really like it in C or C++.

The problem?

Like before a lot of the standard library still lacks pure and it’s impossible to even do simple conversions like converting a double to a string in a pure function.

This destroys completely the usefulness of pure.

A user made an example like this on the forum:

@safe pure unittest
{
    import std.conv : to;
    const y = 3.14.to!string;
}

Compiler error:

`pure` function `foo.__unittest_L1_C12` cannot call impure function `std.conv.to!string.to!double.to`

Source

Obviously no replies on the forum…

5. The mess with “~”

Oh boi this is a funny one…

In D there is the operator “~” that means “concatenation”.

Concatenation != Sum in D

This is a very good design because summing two arrays is technically a different thing than concatenating them, same for strings or numbers, and so on…

The problem is with the symbol itself.

What the D community doesn’t understand is that some keyboards DON’T HAVE THE TILDE “~”.

I know for sure that Italian and Norwegian keyboards don’t have the “~” symbol, there is no way to type it on Windows, besides modding and creating a custom Keyboard layout. Linux doesn’t follow the standard and decided to add them with a non-standard combination (AltGr+ì for Italian keyboards).

So yes the average pro-user that wants to try D and is Italian or Norwegian and using Windows will find out that he/she can’t concatenate objects…

facepalm

6. No references and struct confusion

So okay, D loves to crash when you dereference a NULL pointer, but the situation is even worse because it doesn’t have reference variables like in C++.

The user w0rp wrote a blog post saying that the best way to avoid the evil NULL pointers is to use the D language because thanks to the advantage of having immutable structs and other nice features you can design your code to never stumble upon a NULL pointer.

null and the D Programming Language. by w0rp on 02/09/2013 8:09 p.m.

This is nice and all but the problem is then how I am supposed to program, does the D community want me to abandon the concept of classes? Is this why they actually don’t care about NULL crashing your program? Then why a lot of examples still use classes? Why Thread in D is actually a class and not a struct then? And so on…

7. So you want to switch to/try D

The TL;DR of the TL;DR is that D feels like programming in a jargon of C# with the main disadvantage that NULL exceptions will cause SEGFAULTS instead of NullPointerExceptions exactly telling you were they happened but with the high advantage that being compiled D will perform like C/C++.

8. Now it’s time to apply the survivorship bias

There are a lot of languages out there, and a lot of them failed and were forgotten in the sands of time.

Survivorship Bias should be applied in this case as well.

So we have D that is one of the few survivors almost half dead, instead of improving the features that seem that need improvement, the D developers should apply the survivorship bias and actually check why other languages that aren’t common like: Haxe, Nim and Scala are slowly disappearing or always staying in the shadows even if they technically good.

9 extern(C) and the community

A very powerful feature of D is extern(C), extern(C++) etc…

You can directly link and call other native libraries, you want to draw a window on Linux using D? No problem, you can just link to libgtk-3-dev and call its methods. No need whatsoever for wrappers and bindings.

The only drawback is that D can’t import header files so you need to rewrite the function you want to call with extern(C) before the return value and you are done. (Also you need to rewrite structs and enums if you want to use them)

nothrow pure @nogc @trusted extern(C) void gtk_init (int *argc,char ***argv); 

void main()
{
    ...
    /+
        Can call gtk init here fine 
        provided you linked it 
        with your D program
    +/
    gtk_init(......)
    ...
}

And I forgot to mention that you just need to put the C object file of the library you want to link (if it’s not provided by your system) in the list of source files and D will automatically link to it!

Cool and nice but where is the problem then?

The D community.

They waste so much time in creating bloatware wrappers instead of useful libraries (not naming the D libraries here but you know what I’m talking about probably) when D already offers a native binding method!

There are some D wrappers for a lot of famous libraries that are basically useless, they only increase compilation time, some even 20x, when a developer could have just used extern(C).

A counter-argument is that by creating a D wrapper you are providing a memory-safe interface with the native library, that’s true, but two considerations here:

  1. A lot of those D bindings are bloatware and aren’t just validation layers, but full-fledged OOP libraries wrapping a non-OOP library

  2. If you are already linking D with a C/C++ library then maybe you already know what you are doing and you should use extern(C)

  3. D can’t continue forever to link to external libraries, they should be rewritten in D some time in the future…

10. Conclusion

Just apply common sense really, instead of being perfectionists please add a library to format dates, add NULL checking instead of just whining “the OS already does it by spawning a SEGFAULT so D does not need it”… and please fix the tilde ‘~’ for italian keyboards, maybe add a replacement or something; do you hate Italians and Norwegians so much?

Source