Others have spoken in this long thread about why D is not more popular than X, where X=Go or Rust or what have you. I don't have much to add to this, other than to observe that Nim is good work and hasn't exactly taken over the world and, like D, it doesn't have a major corporate sponsor.
I can only speak from my personal experience. I'm in the process of completing a project to port about 9000 lines of C I wrote 10 years ago to provide me with tools to manage my finances the way I want to. I'm a very experienced software developer and project manager, now retired. I'm certainly out-of-touch with the way programmers work today, but I am very familiar with contemporary languages as a result of this project, as well as a long-standing personal interest in programming languages.
As I observed in another recent post, I considered and rejected Rust, Go, Scheme, Haskell and Nim for this project and chose D. A few comments on each:
-
The main application of my project makes heavy use of gtk and sqlite. In Rust, gtk callbacks are required to be "static", meaning that the closures you pass to the signal connection routines must not make any free-variable references that are not static (don't live as long as the program). I will spare you the details, but if you are using sqlite in those callbacks, a necessity (all the work is done in the callbacks), I contend that there is no way to avoid using "unsafe" Rust code. The Rust community, like D's, is helpful, and I've discussed the specifics with them in gory detail, and no one has come up with a solution to the problems I've encountered, nor have I and believe me, I tried. If I am going to be forced to write unsafe Rust, why put up with all the borrow-checker, lifetime-checker pain? Rust's goal of memory safety without a GC makes we the programmers part of the memory management system. Add to that very long compilation times right in the middle of your edit, compile, debug cycle and it's just not worth it.
-
Scheme is a great language and Chez Scheme is a fine implementation. It's mature, well documented and very fast. I use Scheme for a lot of things. But this project is large enough that the dynamic typing becomes a liability. Too many issues that would be caught at compile time with a static language turn into run-time debugging adventures. There is also an issue with weak type-checking across the foreign-function interface (e.g., all pointers look like void* pointers to Chez, so you can pass the wrong one to C without complaint from the Chez or C compiler).
-
I could have done this project in Go and I'm sure it would have been fine, but I chose D instead based on my preference for the language. The tradeoffs weren't all that different so it came down to personal preference.
-
I can say the same about Nim -- personal preference. And there is a fair amount chatter about compiler bugs on the network that was also a bit off-putting.
-
Haskell is another great language, but the nature of how gtk works forces you into maintaining a fair amount of state the old-fashioned way, rather than passing new state with function calls. If much of your code is going to be old-fashioned imperative, why choose a functional language that has had imperative capabilities glued on?
This brings me to my D experience. It took me a while to learn where the land-mines are. The big one was passing a pointer to C that originated on the D side and then getting burned by the GC because I hadn't retained a reference to the object. It took a long time to debug that one, with help from this community. In hindsight, it would have been a lot simpler if I'd read the warning in the toStringz documentation that spells this out. Someone in this thread said that the GC makes C interaction difficult (I forget the exact phrase used). Nah -- you just need to know about this issue and take care to protect objects that originate on the D side. If they originate on the C side, no problem.
But once I got comfortable with the language, the porting of the C code went fairly quickly and the result is just what I wanted: much more concise, readable (and therefore maintainable) code the performance of which is indistinguishable from the C version (truth be told, most of the heavy lifting is done in sqlite, so I probably could have written this in Python -- ugh -- and gotten acceptable performance). I like being able to debug with gdb when runtime problems do arise and I appreciate the fast compile times. After all, the edit-compile-debug cycle is the inner loop when you are developing.
Overall, I'm very impressed by D. The compiler seems solid, the library functions I've used have all worked properly, and the documentation is mostly good. I think the criticisms that have been directed at D about lacking vision, blah, blah, have been from those who have not used it to produce working software that does what it is supposed to do with good performance. In other words, usable in practice (recall that Einstein said "In theory, there's no difference between theory and practice"). That is the ultimate test and at least for me, D has passed that test.
/Don