HN2new | past | comments | ask | show | jobs | submitlogin

I often see people lament the lack of popularity for D in comparison to Rust. I've always been curios about D as I like a lot of what Rust does, but never found the time to deep dive and would appreciate someone whetting my appetite.

Are there technical reasons that Rust took off and D didn't?

What are some advantages of D over Rust (and vice versa)?



> Are there technical reasons that Rust took off and D didn't?

As someone who considered it back then when it actually stood a chance to become the next big thing, from what I remember, the whole ecosystem was just too confusing and simply didn't look stable and reliable enough to build upon long-term. A few examples:

* The compiler situation: The official compiler was not yet FOSS and other compilers were not available or at least not usable. Switch to FOSS happened way too late and GCC support took too long to mature.

* This whole D version 1 vs version 2 thingy

* This whole Phobos vs Tango standard library thingy

* This whole GC vs no-GC thingy

This is not a judgement on D itself or its governance. I always thought it's a very nice language and the project simply lacked man-power and commercial backing to overcome the magical barrier of wide adoption. There was some excitement when Facebook picked it up, but unfortunately, it seems it didn't really stick.


The compiler situation

I think people forget this. I know a lot of folks that looked at D back when it needed to win mindshare to compete with the currently en vogue alternatives, and every one of them nope'd out on the licensing. By the time they FOSS'ed it, they'd all made decisions for the alternative, and here we are.


How many people were working on the core compiler/language at the time versus Rust? This could explain it.


D has always been an handful of people.


> This whole GC vs no-GC thingy

And I am here, enjoying both. Life is good.


Can you elaborate on the points? I know nothing about D, but I'm just curious about old drama


ooooold drama. Like 2008.

FOSS: DMD was always open source, but the backend license was not compatible with FOSS until about 2017. D is now officially part of GCC (as of v6 I think?), and even the frontend for D in gcc is written in D (and actively maintained).

D1 vs. D2: D2 introduced immutability and vastly superior metaprogramming system. But had incompatibilities with D1. Companies like sociomantic that standardized on D1 were left with a hard problem to solve.

Tango vs phobos: This was a case of an alternative standard library with an alternative runtime. Programs that wanted to use tango and phobos-based libraries could not. This is what prompted druntime, which is tango's runtime split out and made compatible, adopted by D2. Unforutuntately, tango took a long time to port to D2 and the maintainers went elsewhere.

gc vs. nogc: The language sometimes adds calls to the gc without obvious invokations of it (e.g. allocating a closure or setting the length of an array). You can write code with @nogc as a function attribute, and it will ban all uses of the gc, even compiler-generated ones. This severely limits the runtime features you can use, so it makes the language a lot more difficult to work with. But some people insist on it because it helps avoid any GC pauses when you can't take it. There are those who think the whole std lib should be nogc, to maximize utility, but we are not going in that direction.


D and Rust are on the opposite sides at dealing with memory safety. Rust ensures safety by constantly making you think about memory with its highly sophisticated compile-time checks. D, on the other hand, offers you to either employ a GC and forget about (almost) all memory-safety concerns or a block scoped opt-out with cowboy-style manual memory management.

D retains object-oriented programming but also allows functional programming, while Rust seems to be specifically designed for functional programming and does not allow OOP in the conventional sense.

I've been working with D for a couple of months now and I noticed that it's almost a no-brainer to port C/C++ code to D because it mostly builds on the same semantics. With Rust, porting a piece of code may often require rethinking the whole thing from scratch.


> block scoped opt-out with cowboy-style manual memory management

Is this a Walter Bright alt? I've seen him use the cowboy programmer term a few times on the forum before.


The term 'Cowboy coder' has been around for some time. Everybody's favourite unreliable source of knowledge has issues dating back to 2011: <https://en.wikipedia.org/wiki/Cowboy_coding>


This was already a thing in Usenet days, an example from 1998

https://groups.google.com/g/comp.lang.lisp/c/tfzX3Sq96Xk/m/0...


Yeah, I just saw his posts too and picked up the term :)


It makes sense for someone who has read about D to pick up on Bright phrasing.


I think 3 things

1. D had a split similar to python 2 vs 3 early on with having the garbage collector or not (and therefor effectively 2 standard libraries), but unlike python it didn't already have a massive community that was willing to suffer through it.

2. It didn't really have any big backing. Rust having Mozilla backing it for integration with Firefox makes a pretty big difference.

3. D wasn't different enough, it felt much more "this is c++ done better" than it's own language, but unlike c++ where it's mostly a superset of c you couldn't do "c with classes" style migrations


One feature of D that i really wish other languages would adopt (not sure about Rust but i also think it lacks it, though if it has it to a similar extent as D it might be the reason i check it again more seriously) is the metaprogramming and compile-time code evaluation features it has (IIRC you can use most of the language during compile time as it runs in a bytecode VM), down to even having functions that generate source code which is then treated as part of the compilation process.

Of course you can make codegen as part of your build process with any language, but that can be kludgy (and often limited to a single project).


Arguably, most of the metaprogramming in D is done with templates and it comes with all the flaws of templates in C++. The error messages are long and it's hard to decipher what exactly went wrong (static asserts help a lot for this, when they actually exist). IDE support is non-existent after a certain point because IDE can't reason about code that doesn't exist yet. And code gets less self-documenting because it's all Output(T,U) foo(T, U)(T t, U u) and even the official samples use auto everywhere because it's hard to get the actual output types.


It is quite ridiculous to place C++ metaprogramming and D's. For one in D it's the same language and one can choose whether to execute compile time constant parts at compile time or run time. In C++ it's a completely different language that was bolted on. C++ did adopt compile time constant expressions from D though.


I'd say D's template error messages are much better than C++'s, because D prints the instantiation stack with exact locations in the code and the whole message is just more concise. In C++, it just prints a bunch of gibberish, and you're basically left guessing.


No, templates are only needed to introduce new symbols. And D templates are vastly superior to C++. D's superpowers are CTFE, static if, and static foreach.

auto is used as a return type because it's easy, and in some cases because the type is defined internally in the function and can't be named.

You would not like the code that uses auto everywhere if you had to type everything out, think range wrappers that are 5 levels deep.


Rust has procedural macros, which turn out to be a good-enough substitute for real compile-time reflection for surprisingly many use cases, though nowhere near all of them. (In particular, Serde, the universally-adopted framework/library for serializing and deserializing arbitrary data types, is a third-party library powered by procedural macros.)

Real compile-time reflection is in the works; the very earliest stages of a prototype implementation were released to the nightly channel last month (https://github.com/rust-lang/rust/pull/146923), and the project has proposed (and is likely to adopt) the goal of completing that prototype implementation this year (https://rust-lang.github.io/rust-project-goals/2026/reflecti...), though it most likely will not reach the stable channel until later than that, since there are a whole lot of complicated design questions that have to be considered very carefully.


"Powered by" is an understatement, Serde would be unusable without procedural macros. Deserializers use a ridiculously verbose visitor pattern that's completely unnecessary in a language with move semantics, it should have been a recursive descent API.

Using serde_json to accurately model existing JSON schemas is a pain because of it.

I personally find third-party deriving macros in Rust too clunky to use as soon as you need extra attributes.


> Are there technical reasons that Rust took off and D didn't?

My (somewhat outdated) experience is that D feels like a better and more elegant C++. Rust certainly has been influenced by C and C++, but it also took a lot of inspiration from the ML-family of languages and it has a much stronger type system as a consequence.


D has much better metaprogramming compared to Rust. That has been one of the only things making me still write a few D programs. You can do compile time type introspection to generate types or functions from other elements without having to create a compiler plug-in parsing Rust and manipulating syntax trees.

Rust has some of the functional programming niceties like algebraic data types and that's something lacking in D.


More like the companies that jumped into D versus Rust, D only had Facebook and Remedy Games toy a bit with it.

Many of us believe on automatic memory management for systems programming, having used quite a few in such scenarios, so that is already one thing that D does better than Rust.

There is the GC phobia, mostly by folks that don't get not all GCs were born alike, and just like you need to pick and chose your malloc()/free() implementation depending on the scenario, there are many ways to implement a GC, and having a GC doesn't preclude having value types, stack and global memory segment allocation.

D has compile time reflection, and compile time metaprogramming is much easier to use than Rust macros, and it does compile time execution as well.

And the compile times! It is like using Turbo Pascal, Delphi,... even thought the language is like C++ in capabilities. Yet another proof complexity doesn't imply slow compile natives in a native systems language.

For me, C# and Swift replace the tasks at work were I in the past could have reached for D instead, mostly due to who is behind those languages, and I don't want to be that guy that leaves and is the one that knew the stack.


> Many of us believe on automatic memory management for systems programming

The problem is the term "systems programming". For some, it's kernels and device drivers. For some, it's embedded real-time systems. For some, it's databases, game engines, compilers, language run-times, whatever.

There is no GC that could possibly handle all these use-cases.


But there could be a smoother path between having a GC and having no GC.

Right now, you'd have to switch languages.

But in a Great Language you'd just have to refactor some code.


Why would you have to switch languages? There are no languages with 'no GC', there are only languages with no GC by default.

Take C - you can either manually manage your memory with malloc() and free(), or you can #include a GC library (-lgc is probably already on your system), and use GC_malloc() instead. Or possibly mix and match, if you're bold and have specific needs.

And if ever some new revolutionary GC method is developed, you can just replace your #include. Cutting-edge automatic memory management forever.


Except there is, only among GC-haters there is not.

People forget there isn't ONE GC, rather several of possible implementations depending on the use case.

Java Real-Time GC implementations are quite capable to power weapon targeting systems in the battlefield, where a failure causes the wrong side to die.

> Aonix PERC Ultra Virtual Machine supports Lockheed Martin's Java components in Aegis Weapon System aboard guided missile cruiser USS Bunker Hill

https://www.militaryaerospace.com/computers/article/16724324...

> Thales Air Systems Selects Aonix PERC Ultra For Java Execution on Ground Radar Systems

https://vita.militaryembedded.com/5922-thales-execution-grou...

Aonix is nowadays owned by PTC, and there are other companies in the field offering similar implementations.


Look, when someone says "There's no thing that could handle A,B,C, and D at the same time", answering "But there's one handling B" is not very convincing.

(Also, what's with this stupid "hater" thing, it's garbage collection we're talking about, not war crimes)


It is, because there isn't a single language that is an hammer for all types of nails.

It isn't stupid, it is the reality of how many behave for decades.

Thankfully, that issue has been slowly sorting out throughout generation replacement.

I already enjoy that nowadays we already have reached a point in some platforms where the old ways are nowadays quite constrained to a few scenarios and that's it.


> Are there technical reasons that Rust took off and D didn't?

This talk explain why, it's not technical: https://www.youtube.com/watch?v=XZ3w_jec1v8

> What are some advantages of D over Rust (and vice versa)?

Advantages for D: Build faster, in typical programs you would need about 20 packages not 100, COM objects, easy meta-programming, 3 compilers. GC, way better at scripting.

Advantages for Rust: borrow-checker is better. rustup.


> This talk explain why, it's not technical: https://www.youtube.com/watch?v=XZ3w_jec1v8

Really good talk, I remember watching it when it came out. Elm is what got me looking into FP several years ago, a nice language it was.


> Are there technical reasons that Rust took off and D didn't?

Yes. D tried to jump on the "systems programming with garbage collection" dead horse, with predictable results.

(People who want that sort of stupidity already have Go and Java, they don't need D.)


> (People who want that sort of stupidity already have Go and Java, they don't need D.)

Go wasn't around when D was created, and Java was an unbelievable memory hog, with execution speeds that could only be described as "glacial".

As an example, using my 2001 desktop, the `ls` program at the time was a few kb, needed about the same in runtime RAM and started up and completed execution in under 100ms.

The almost equivalent Java program I wrote in 2001 to list files (with `ls` options) took over 5s just to start up and chewed through about 16MB of RAM (around 1/4 of my system's RAM).

Java was a non-starter at the time D came out - the difference in execution speed between C++ systems programs and Java systems programs felt, to me (i.e. my perception), larger than the current difference in performance between C++/C/Rust programs and Bash shell scripts.


It still is an unbelievable memory hog. It got faster though.


Go wasn't around when D was released and Java has for the longest time been quite horrible (I first learnt it before diamond inference was a thing, but leaving that aside it's been overly verbose and awkward until relatively recently).


Is Java even a "systems programming" language?

I don't even know what that term means anymore; but afaik Java didn't really have reliable low-level APIs until recently.


Depends if one considers writing compilers, linkers, JITs, database engines, and running bare metal on embedded real time systems "systems programming".


so, "yes", but with added sarcasm? :D




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: