76 comments

[ 2.2 ms ] story [ 140 ms ] thread
D looks like a really interesting language, I had never checked it out prior to reading this. unittest blocks look like they'd be super helpful. And it has modules, which I consider a must-have.

In what areas would D excel? What are its downsides? What did you like and dislike the most? I'd be really interested in hearing about people's experiences.

As a D programmer currently making a small game engine + networked rts game in the language, invariant blocks are another thing I really enjoy about the language: http://dlang.org/contracts.html#Invariants

Lets you specify contracts which are asserted on construction and destruction, it's great.

The meta programming is also wonderful for things like serialization of data, simply iterating over a type's members at compile-time to generate serialization code, cutting out much bloated code. It's worth noting that it's metaprogramming for humans, _compared_ to c++, but sometimes leaves a bit to be desired documentation-wise, all the building blocks are there, but sometimes you'd like to not need to reinvent the wheel every time you attempt some metaprogramming-related task.

Things I don't enjoy include the core language's reliance on the GC, including things like exceptions relying on GC allocations.

Thankfully they've made it a bit easier to track down things which may allocate gc memory lately with accompanying flags to the compiler, which prints a trace of where it may happen.

I'm always on the look out for improvements to C++, and it's been a while since I looked at D... Hope you don't mind if I ask you a couple questions.

Can you still turn off the GC? Lets say I don't like exceptions, and that I don't mind implementing library code on my own, would turning GC off impact anything else?

How is the story for deploying executables to mac/win/lin? Is it as easy as C/C++?

Also, do you know if anybody's shipped high quality games with it before? It's been a while now, I'd hope so, but I haven't heard of any. Pretty sure no AAA games have used it but maybe some indie?

> Can you still turn off the GC? Lets say I don't like exceptions, and that I don't mind implementing library code on my own, would turning GC off impact anything else?

You can turn off the GC in the sense that memory allocation will always request more memory from the OS instead of occasionally starting a collect cycle. However, you can alternatively use manual memory management (malloc/free, allocators/RAII on top of that, etc.), which will never trigger the GC.

> How is the story for deploying executables to mac/win/lin? Is it as easy as C/C++?

Yes. I think for Posix systems, you can optionally link dynamically to the runtime/standard library.

> Also, do you know if anybody's shipped high quality games with it before?

IIRC, Remedy Games used D for engine scripting on XBox 360. Manu Evans talked about this at DConf 2013.

Here's a commercial indie game written in D: http://www.inventivedingo.com/mayhemig

Well, a couple things about it make me nervous, but CTFE and a not horribly broken compilation model might make it worth trying out next weekend...
You can definitely survive without the GC, personally I've gone through eliminating exceptions entirely and implementing my own allocators throughout.

There are a few gotchas sometimes, like array literals of certain kinds sometimes allocating when you don't expect them to, but these can usually be sorted. Something which also might bite you, but can be caught with the gc-tracking compiler flag, is the fact that delegate _closures_ use the GC, regular delegates however will not need the GC, one thing to keep in mind.

There's quite a bit of info about how the GC impacts things, and how to get by without it around, so I think you'll survive without it's presence.

Lately as well, efforts to annotate portions of the standard library which don't use the GC at all with a special annotation @nogc has been underway, which makes it explicit if something can allocate or not (this is transitive, so a @nogc annotated function can only call @nogc annotated functions which can't do any gc allocation in turn).

I could probably survive not using most of the standard library (I might try to do this anyway to avoid issues with deployment, as I have done in the past in C++).

I'm not a huge fan of closures in many cases (if they outlive the scope of their defining function I think it leads to unclear code), so the fact that they might allocate is not a huge deal to me. Array literals silently allocating GCed memory concerns me greatly however...

I remember hearing about efforts to remove a lot of the reliance on the GC, and I guess I was hoping that that was further along than it sounds like it is.

Still, I'll try not to pass judgement until I try it out on something small. There are a lot of other potential issues unrelated to the GC that would probably be dealbreakers for me.

The array literals problem isn't so bad, the thing is static arrays in D are distinct types, so you'd say int[2] = [1, 2]; which would go on the stack, but doing int[] = [1, 2]; would allocate since it would be a dynamic array then.

Good luck with trying it out, you make tradeoffs as with any other language :)

A bit of an overlooked area where D excels are its support for transitive immutability and function purity. We're discovering more and more things that are now practical because of this.
I'm curious how many people out there on HN actully use D and what for? I don't typically see D based projects here on HN so it would be interesting to find out about any use cases where D was found a perfect fit.
WalterBright uses it in his compiler.
He's a little more involved in D than using it in his compiler :)
>WalterBright uses it in his compiler.

Ironically, the dmd compiler is written in C++.

D didn't exist when the dmd compiler was written. But Daniel Murphy has written a C++ to D converter, and it's looking like the next release will have dmd written in D.
>it's looking like the next release will have dmd written in D.

Is that going to make it trickier for GDC/LDC to stay in sync with DMD? (Either way, it's exciting news!)

Tricky or not, they're on board with the jump.
How will you then bootstrap it on new platforms? Will it become reliant on cross compilation for bootstrap?
It's being replaced this year by a D version.
I use D for ... almost everything. https://github.com/CyberShadow?tab=repositories

Here's a bit of code from a personal shopping comparison program I wrote a few days ago, which combines some standard library constructs with my own libraries:

  string findProduct(string name)
  {
      return
          ("http://www.tp-link.com/en/search/?q=" ~ encodeComponent(name))
          .download
          .readText
          .toXML
          .xmlParse
          .I!(doc => zip(
              doc
              .findAll("#productResult > li > dl > dt > a")
              .map!(e => e.attributes["href"])
          ,    
              doc
              .findAll("#productResult > li > dl > dt > a")
              .map!(e => e.children[$-1].text.strip)
          ))
          .filter!(t => !icmp(t[1], name))
          .I!(r => r.empty ? null : "http://www.tp-link.com" ~ r.front[0])
      ;
  }
I know your projects! You made RABCDasm, which is used extensively on a certain game I used to play around in, people are still using it. Hah, I mostly asked this question because I was reminded of you, you're one of the first developers I saw who does most of their work in D.

Thanks for all your hard work, there's people out there who really found RABCDAsm really helpful, and it inspired a lot of fun software in the process.

Ah, thank you! Long live game modding ;)
95% of the code I work on is D.

D fits lots of purposes (more than C++), but I'm only going to talk about scripting.

The minimalistic approach for the C++ standard library makes C++ inappropriate to replace, for example, Bash scripts. In C++, you can't do any operation on the file system (erase a directory, get file size, list files, create pipes, ..) in a portable way. You can't create processes in a portable way.

The D standard library (aka Phobos) doesn't suffer these limitations. Which means you can write very high-level code using only a few (readable) lines. By adding a shebang "#!/usr/bin/env rdmd" at the beginning of your D programs, you can execute them without prior explicit compilation, like: ./myProgram.d

I've been porting all my Bash scripts to D. The code runs incredibly faster, and now I can have structs again!

I did some hobby stuff with it. But I'm afraid that I didn't use it for real stuff. A few weeks ago I try to use it to write a tool to update our Java webservices from the latest Maven deploy (I'm afraid that I work as Java programmer :( ). Sadly I got issues with linking against std.net.curl , and I end writing a bash script for that.

I really enjoy a lot more writing on D, but I keep finding the issue that I need to interface with C++ libs for something (for example Qt 5 for an emulator GUI) or weird errors like these problem with std.net.curl on Ubuntu 14.04 . If not was for that, I would wrote the Trillek virtual computer on D.

Did you consider their wiki page on GUI Libraries?

http://wiki.dlang.org/GUI_Libraries

Just thought I'd share, maybe you overlooked it and this might be helpful for future projects? Good luck!

I know and try GtkD (https://github.com/Zardoz89/DEDCPU-16). It's fancy, but at the end you would find that you are always trying to do a mental map between the Gtk documentation and how this is translated to D. Plus is Gtk.

Also, I played a few with Qt 5 on C++... I would like to have updated binding of Qt for D. qtd and dqt looks that are abandoned. :S

DQuick looks interesting, perhaps I would rewrite my fontmap editor with it.

PD: If I look that I hate a bit Gtk, I would only say that with buggy graphics drivers (ie ATI/AMD cards on Linux), Gtk usually have horrible graphical glitches, when Qt simply works fine.

What I'd particularly like to see is an analysis of D vs. Rust. Both have been touted as systems programming languages to replace C/C++, and I'd be curious to see a breakdown of their strengths and weaknesses compared to each other.
It would take an expert in both languages to do it. My knowledge of Rust is fairly limited. In particular, every language has its own idiomatic way of doing things (the D Way, the Rust Way), and to compare one has to be cognizant of those idioms.
D is a fantastic language. C++ is so difficult to unseat as a systems language now since it is back as a moving target which is both evolving and has extremely robust tools to go with it. Challenging it on the language level is not enough.
Yeah. C++ has so good tooling that despite what new language I try, I always hit some implementation, ecosystem or tooling issue that always leads me to conclude I would have been more productive with C++. Which sucks monkeyballs as aesthetics go.
> D has no need for a preprocessor

How does this work, specifically conditional compilation? I have lots of code like this:

   #if __APPLE__
      /* do things the OS X way */
   #else
     /* do things the Linux way */
   #endif

Where the OS X way calls functions that do not exist on Linux, and vice-versa. How does D handle this?
Check out https://github.com/D-Programming-Language/phobos/blob/master... at line 33 and on. You'll see: version (Windows) { ... } etc. For the specification on how this works:

http://dlang.org/version.html

The salient point is that conditional compilation in D is not text based, it is AST based. Furthermore, for 'static if', the conditional expression has access to the full symbol table and power of the D language - it is not a separate preprocessor language with its own rules and separate symbol table.

Thank you for the reply. That's very elegant!
(comment deleted)
Can it do more complex ifdefs - with or's and and's etc?
'static if' can - it has full access to the language.
Lack of a preprocessor does not imply lack of conditional compilation:

http://dlang.org/version.html

The constructs are simply built into the language.

This has considerable benefits: you can use e.g. `static if` to enable/disable code based on conditions which refer to constants declared in the program (there is no longer a separate namespace for preprocessor defines and program constants), and with CTFE, you can use any expression that can be evaluated during compilation.

The language it's itself his own preprocesor, thanks to CTFE. I think that it is what I love more of D.

    version (Posix) {
      version(OSX) {
        // Weird stuff on OSX
      }
    // Sane stuff for Linux or FreeBSD
    }
    version (Windows) {
      // Weird stuff for Windows
    }
But think that this is processed by the compiler, not by a text pre-processor. Also, you can use your own version stuff, for example here : https://github.com/Zardoz89/nBodySim/blob/master/source/app.... there is a "PFor" version to allow to compile a version of the program that uses a parallel foreach (an N Body simulator)
I was working on a similar article just a couple of weeks ago for the D wiki, but I wanted to focus on the really big things, and I want to include more examples:

http://wiki.dlang.org/Coming_From/C_Plus_Plus_WIP_article

Yeah, my article is a bit of a quickie and not very good, I didn't expect people would post them here and on reddit. Moreover, it isn't a big picture post.
D looks great, but I feel like depending on a GC is kind of a deal-breaker. If that is accurate, then D fills the same niches as Google's Go rather than C++'s. Rust looks more like a proper replacement for C++.
You can still "delete" by hand in D. The GC just does it if you fail to.
Is now the time for D? I really wonder, I am not really sure. Certainly a lot of languages go thru a period of obscurity before success, but I'm still uncertain.

The one issue that sticks for me was the dual standard libraries. Just seems so messy.

The dual library issue ended 7 years ago or so.
enh shows how much i know.

Honestly, I'm pretty excited for Rust. Having a strong proof of lifetime enforced by compiler is very compelling idea.

> D has a package manager. C++ has none that is popular in its community. Therefore, using a third-party library is many times easier.

This comes up all the time in reference to C++. C++ doesn't need a package manager because it has excellent support from distro package managers. Most libraries are in the system package manager. And yes, sometimes you need a newer version of a package or one not quite widely-used enough to be in the system package manager, in which case you need to do compile it yourself or install it manually. But that is a problem common to all package managers and there is nothing about D which will make it any easier.

Almost every C++ codebase out there vendor all dependencies. Looks like they are not using the system package manager. Windows has no package manager with such library releases. Language package managers have problems, but they do make the work easier.

Anyone here unhappy with pip?

> Almost every C++ codebase out there vendor all dependencies. Looks like they are not using the system package manager.

Yeah, e.g. Chromium. But that was also the reason why Fedora refused to provide packages for Chromium. Distros don't like projects that include their own versions of libraries because it goes against how things are supposed to work (maintenance and, by implication, a security nightmare). I know that there are many C++ projects in the various distro package repos, and no way do 'most of them' include their own copies of dependencies.

In the closed source world I'd say most codebases are like Chromium (difficult to say of course). It's a bit like distributing an application with binary libraries and a no-go for security indeed.
Yeah I am sure it's very common in closed source or internal systems. One place I worked at recently did that. All of my comments are about open source systems such as Linux and BSD.
It might not be usable/in use - but doesn't nuget support c++? http://blogs.msdn.com/b/vcblog/archive/2013/04/26/nuget-for-...

> Anyone here unhappy with pip?

Pip has (had) a number of issues (mostly related to pypi/availability) -- but pip+virtualenvs is something I use all the time, and am very happy with.

The ease with which one can simply:

  virtualenv some_experiment # --no-site-packages
    # is now standard! yay!
  ./some_experiment/bin/pip install -U pip distribute
    # sadly needed -- but gets us pip list --outated, which
    # is very helpful
  ./some_experiment/bin/pip install <thing-to-test>
And then just work with that, without even having to mess around with sourcing the "activate" script etc for most packages is great. No clutter under /usr/local, no broken system tools due to some dependency being pulled in etc.
The operating system package manager is supposed to provide packages for libraries that are required to run the rest of the operating system. Not libraries you need for development.

Package managers for development allow things such as installing multiple versions of a library, creating "sandboxes" with specific versions of libraries, and sometimes they are also the de-facto build system for a language.

The OS package manager isn't doing the same job and has very different requirements. Not all libraries (especially ones that are usually built statically or header-only) end up in an OS package manager. Typically OS package managers don't bundle any libraries that are not required by one or more of applications in the package repository.

So no, an OS package manager doesn't cut it for C or C++ development. They don't ship all the libraries and they can't do all the things you need for serious development.

As a C and C++ developer, this pisses me off constantly. Even though most libraries are easy enough to fetch these days with Git, there's no standard way of configuring, building and installing them. And no OS package manager has ever been able to provide all the libraries I need.

(Note: my frame of reference is experience with UNIX-like systems such as Linux and the BSDs, and even MacPorts on OS X.)

  The operating system package manager is supposed to
  provide packages for libraries that are required to
  run the rest of the operating system. Not libraries
  you need for development.
Distro repos do provide many of the packages you need for development because you need to be able to compile all of the C++ applications and libraries in the distro repo, of which there are many.

  Package managers for development allow things such as
  installing multiple versions of a library, creating
  "sandboxes" with specific version
Distro repos often include multiple versions of libraries because not all of the crucial applications and libraries in the repo are upgraded at the same speed.

  The OS package manager isn't doing the same job and has very
  different requirements. Not all libraries (especially ones that
  are usually built statically or header-only) end up in an OS
  package manager. Typically OS package managers don't bundle
  any libraries that are not required by one or more of
  applications in the package repository.
Fair enough, and for this reason a language-specific PM will most likely have more libraries available, so I concede that point. However, I seriously doubt that a single group of people could be better at providing packages for all the major combinations of kernel, distro, and CPU architecture than the collection of distro groups. Just imagine how difficult that would be!

C++ is different because it is very intertwined with the system. For D it makes sense at this point because it doesn't have the existing distro PM support that C++ does. Once crucial parts of the system starts depending on D the situation might change.

> Distro repos do provide many of the packages you need for development because you need to be able to compile all of the C++ applications and libraries in the distro repo, of which there are many.

I think it's more along the lines of the distro's package manager's responsibilities should be different from the language's PM. Although I do find myself in agreement with you that the distro's PM is sufficient for C/C++

Yes, a distro package manager can partially solve this issue but there are some corner cases where this fails. Though I partially agree with you: my OS package manager can provide me with the C and C++ libs I need most of the time.

To name a C++-specific pain in the ass: Boost. The Boost libraries make minor, incompatible changes every now and then (which is good), requiring applications that use Boost to either specify a certain version that they can work with or bundle the Boost libraries with the application source (which is bad).

And "development" package manager should be able to deal with the situation above, but distro package managers don't really work here. There are several libboost-foo-1.xy.z packages available but it may be that none of those will work with a certain application you're trying to build (either too old or too new).

This situation is handled by development package managers by pinpointing the exact version (or range of versions) of a library an application depends on. This also allows specifying compiler/interpreter version(s) an application works with. Some of my projects depend on features that are only available in recent GCC versions (__builtin_shuffle), but that requirement can only be informally specified in the README, nothing enforces it (leading to unnecessary bug reports).

This is also what git submodules does but without a standard build system, it only solves half of the problem (and may create new problems).

I think you and I can both agree that this situation is less than ideal. Using just one package manager application should be enough, there's a lot of overlap between what a distro package manager and a development package manager do. And it's a huge waste of engineering resources to maintain language-specific package managers such as pip/gem/cabal/cpan.

"Next generation" package managers such as Nix and GNU Guix should be able to address these issues, but they are yet to be widely adopted. Unfortunately those applications are based on less-than-mainstream languages (Haskell and Guile Scheme, respectively) which might scare away potential adopters.

Speaking of package managers, looks like the ssl-cert for dlang.org is expired (and has been for more than a year) -- which leaves most of us with one less way to try to verify the installer, as: https://dlang.org/gpg_keys.html is only available via a untrusted channels.
D is a awesome language to work with, it's got many useful language features that make the activity of code writing a pleasure. - I hope this criticism is taking constructively.

However not a beat a dead horse, but if you want to process more than a trickle of data in it you run into problems with the GC really quickly. I really feel the language would be better off without the GC.

These are not the same issues address by the JSON compiler post or w/e that surfaces a couple months ago.

From what I can tell, theres a global lock around everything in the GC, including allocations. In a multi-core world, this just simply doesn't work and it one of the major pain point of the language. I write data-intensive processing on high core count machines (32), and have had to resort to 0-allocation strategies, or in map-reduce contexts actually sharding at the process level, writing the results to disk, and then running a reducer process over the results.

You can write performant D code, but you give up large amounts of code safety. It's essentially just whatever you'd write in C++ without the ownership semantics it gives you.

You can't have a core part of your language being an essentially unavoidable massive point of contention.

I've literally seen 20x or more speedups in multithreaded cases just by making sure I reuse every buffer rather than create new ones.

I feel this is really holding back an otherwise great language to work in.

This is discussed in the reddit thread in more detail.

While true, it is more a consequence of quality not of having a GC.

D with an Hotspot comparable GC quality would be quite good.

I got a speedup of around 13,32 on a 16 core Opteron machine a few years ago, using a simple parallel foreach on a N Body problem simulator. I didn't do anything special for it.

I thought using SIMD to accelerate it more on the integrator and acceleration calculation, inside of the parallel for.

Unless you are creating or destroying bodies then your n-body implementation won't need to allocate any memory will it? So is it relevant to what he's talking about?
> I've literally seen 20x or more speedups in multithreaded cases just by making sure I reuse every buffer rather than create new ones.

Reuse rather than free and reallocate is a core practice whenever you feel the need for speed, regardless of the memory allocate strategy used.

For some very fast D code:

https://github.com/facebook/warp

Minimizing the amount of heap memory allocated is a core strategy.

Thanks for responding. I've seen this code used an an example before actually.

Not that buffer reuse/avoiding heap allocations was unknown to me, it was just surprising to see this in an application that spent most of it's time waiting on the network.

I will say as a positive point that the equivalent D code to a C++ implementation was much cleaner due to build in array slicing among other things.

There are other areas where heap allocations are not so avoidable however (some hashmaps, some std's). My main point is that like at all languages, heap allocations are slow, but here they bear an unnecessarily large contention factor.

I really like D so I hope this is helpful feedback.

"Reuse rather than free and reallocate is a core practice whenever you feel the need for speed"

The problem with this conventional wisdom is that it defeats other optimisations. If you free, use, and deallocate a block of memory within a compilation unit, a compiler can transparently allocate it on the stack, or even keep it in registers

If you use a free-list the objects are always escaped, and the same optimisations can't be applied to them.

This is particularly true for small temporary objects, like an intermediate vector (as in coordinates) object.

As aside:

I just discovered that the language authors are converting the std library (phobos) to be "no GC".

It's a little more nuanced than that. Phobos is moving towards a more pipeline style, of which http://dlang.org/phobos/std_algorithm.html is a standout example.

Algorithms, by and large, do not need to dynamically allocate memory. By converting more of Phobos to being algorithms, they become agnostic to whatever allocation method is used. Allocation strategy becomes a high level decision, rather than a low level one.

> No more header files, today

> Even when C++ compilers implement modules and you can finally use them, headers will still survive alongside modules for backward compatibility.

Uh, that one is just weird. So, a reason to use D is because C++ can support older projects?

I use C++ but I don't really like it, but ... we need all the libraries that exist in C++ rewritten in D. And also, the same compiler support in the development frameworks. Otherwise, it will be a failure.