Hacker News new | past | comments | ask | show | jobs | submit login
Idioms for the D Programming Language (p0nce.github.io)
158 points by crazypython on Feb 11, 2021 | hide | past | favorite | 81 comments



This can get downvoted to oblivion, but i fell for DLang first time i wrote a hobby raspberry pi gpio library.

It just worked. It compiled without hassle. The language was easy to understand - i first read about a few days prior to writing my lib.

I absolutely think this language should get more attention, and probably it should explore wasm a bit more. I know webdevs love easy to read languages and DLang is an ideal candidate for replacing javascript in the browser via wasm.

All it needs is a nice package manager and a set of basic web libs to use in the browser - not the DOM kind of libs, but for large’ish tables and data manipulation, a bit of audio and video editing and perhaps webgl integration to showcase what it can do.

/end of babbling


I like to write really basic little games to kill time. Stuck on a flight? Clone tetris or minesweeper or whatever. And of course I use D.

Well, I wrote a version of my support library for those games for webassembly too and you can play some of them online!

http://webassembly.arsdnet.net/

None of them are "finished" per se, I'd be on a strict time limit and just left it where it landed when I ran out, some not even really working, but there's some little playable chunks there. Tends to be 60KB or so of webasm, really not too bad (no need for the emscripten bloat etc since I did it all myself)

It amuses me to compile the same program for Windows, Linux, and the browser without modification.

(that's all I personally use webassembly for though, since I'm not a fan of SPAs...)


That's really cool, thank you for sharing! It is neat to see a bit longer form D code in more than just sample tutorials.


i love D, i only wish story where non-gc is needed would improve (more allocator work, more gc free runtime etc)

after trying zig, i also wish C interop was as smooth, but zig has advantage of shipping a clang compiler as library, D could do the same since they got LDC (with LLVM)

i move between zig/rust and D; i'm happy to say that we can live in a world where we can totally ignore c++


@nogc is growing, and memory safety will also be improving, just that we've basically reached end of what we can do before reaching the hard problems - we're definitely not stopping we just need to get any changes to the language right.

Also remember that the GC is entirely written in D, it is possible.


There's also Calypso, an LDC fork that can process C++ headers directly. It should in theory also work with C.


why a fork, and not a PR to LDC? fragmentation is a bad thing in my opinion


Because merging an increasingly large subset of a c++ compiler into a compiler for a different language is a recipe for disaster if you're unlucky.


I don't know how exactly things works, but zig approach is very nice, i wish it was possible with D too

When i say available, i mean available out of the box


I've heard before that there is a schism in the D community between two different options, but never can remember what it is. Something that fragments the ecosystem?


D's biggest problem at this point is that everyone (including me) vaguely remembers that period where it was in limbo between different design strategies, and consequently frets: "is it stable yet?".

Luckily, that seems to finally have reached a "yes!". Development continues, but nobody's getting the rug pulled out from under them anymore.


> finally

That really arrived with Andrei Alexandrescu's book which was 10 years ago now.


I heard about this schism less than 5 years ago so there's probably some pages/blogs/talks that need to be updated.


It's mostly second hand commentary.

HN is an outlier in that people have even heard of D, for some perspective.


There were two stdlibs in D1 (the official one called phobos, and tango which had a more "java-like" feel). I haven't been following D for years, but it looks like Tango sort of died off when work on D2 started to get traction[0]

[0] http://www.dsource.org/projects/tango/forums/topic/920


The api wasn't really the problem, it was more about the language runtime. Upstream wasn't exactly receptive to big changes, so a segment of the community forked and made the changes themselves. But since these hit the core language, it led to some incompatibility.

Part of the evolution of breaking changes that would eventually be labeled "D2" was upstream merging in those incompatible bits. So the user-level API of Tango kinda died out - kinda, it is still around but not many people still use it - (as did the Phobos user-level API from that era btw, most of it anyway got replaced in the evolutionary process too) but the actual runtime parts actually just got merged upstream, bringing the two diverging branches together, and are now called "druntime".


Interesting. I guess that was all after my stint playing w/ D. I had never heard about this Amber effort until I googled for tango today, for example. From my perspective as a user, it definitely felt like the API divide was a problem - there were things that were only available on top of phobos and other things that were only available on top of tango and you couldn't use both together.

But yes, all of this was weeeeell over a decade ago. Despite having experienced this friction back then, I still think of D as an extremely productive/pragmatic language with a snappy compiler. Some of the stuff that pops up here and there about new developments in D2-land are also very interesting. If anyone's on the fence about it, I would definitely recommend giving it a shot.


See the api divide wouldn't matter if the runtimes were merged (this actually happened, you can still use Tango today if you like) since you'd just import the other modules and have them side by side. Sure some libs might depend on std.socket and others on tango.socket, but that's not a huge problem since they can exist side-by-side. You might just need an adapter if you wanted to pass a socket from one lib to another that uses the different thing. Slight hassle but totally solvable.

But with the incompatible language runtime components, you couldn't merge the user level libs either. The base Object and Exception classes worked one way in one lib but another in the other and both used the same underlying function names leading to a linker conflict. The user-level namespaces in D are always isolated to modules, but this low level language runtime is global.

That was solved when the Tango requirements got merged upstream.


Thanks for that context. I wish that information was more obvious and well-documented since it seems like enough people still don’t know the details. D does seem useful and it’s something I want to pick up someday but had been holding off because that situation sounded so demotivating.


What irks me is this stuff is all from before 2007 - that's when the runtime support lib branches were merged - yet social media comments make it sound like it is today.

I'm a bit irked personally at people saying "D1" vs "D2" too. I use scare quotes because they actually came out at about the same time. There's only really one D language that's gone through a consistent evolutionary process.

In January 2007, a "stable" branch was arbitrarily forked off the language. This was labeled "D 1.0". It wasn't exactly stable yet; it still got some new features and even some breaking changes applies to it from the dev branch, but most the more experimental stuff didn't get merged.

In summer 2007 - mere months later - the "dev branch" got arbitrarily rebranded "D 2.0" There was nothing particularly special about that release, it didn't even have any real breaking changes. It was just slapped with a new label, but this was the ongoing evolution D has had since the beginning.

A little while later, the dev branch, aka D2, did start getting some more major breaking changes, like the const and immutable system being added (at first nothing broke, but then the type of string literals was changed from char[] to immutable(char)[] and that was a fairly big change since strings are used everywhere), while the stable branch, aka D1, would start to get only bug fixes.

People call this a "community split", but that's just not really how it happened. The stable branch was mostly maintained for a few corporate clients who didn't want to adapt to an array reallocation change in the runtime (despite general agreement the new way was better, they were just heavily invested in the old way and it would take some time to confirm their code wasn't adversely affected) while most everyone else embraced the ongoing evolution.

There were a few years of kinda obnoxious churn - I remember being quite annoyed when the std.string tolower got renamed to toLower among other "consistency" updates - but like it really wasn't that big of a deal for most of us.

I think it was a mistake to call it "D1". It should have probably just been something like "D extended support edition". But the name was what it was and online commenters continue to misrepresent what actually happened now, 14 years [!] (yikes i've been in the community a long time now) later.


You might mean the D1 vs. D2 schism. That was ages ago, it hasn't been a live issue for a very long time.


IIRC there were two different standard libs at one point. I don't believe that's an issue anymore.


I've been in the D community since 2009. There is no schism.


There was a schism the best part of 15 years ago now.


D does have a package manager named dub, it works well.

https://code.dlang.org/


> it works well

it ... works

That's as much as I think can be said for it. Dub is garbage. It's too complicated, too rigid, and it does too little. It's also slow for larger projects because it doesn't do incremental builds.


Is the lack of incremental compilation aproblem with dub or with D compiler in general?


It's a problem with dub. The D compiler operates basically exactly like a C compiler would as far as I'm aware.

Note that in most cases an incremental build isn't really required for D because for moderately complex projects you're often limited by linking speed, not compiling speed.


Both. Incremental compilation is possible to an extent, and reggae[0] does it. However, due to the semantics of d imports and templates, compiling a module will require at least cursory parsing and semantic analysis of all the modules it imports. Meaning that for a binary with a single entry point, modifying pretty much any module will require recompilation of the top-level module, which means there's a certain degree of incrementality you can never reach.

0. https://github.com/atilaneves/reggae


dub does incremental builds.


On a per-file basis? Afaik it works with package granularity, so if you change one line of a package, you're SOL.


Per-package translation unit are faster than per-file translation units.


One thing D does have in its favor over most of the competing alternatives is a fairly mature ecosystem story, with multiple implementations of the compiler, decent docs, libraries for common domains, and a lot of "use hours and eyeballs" on the project as a whole that have brought up and addressed obscure issues. While it has accumulated some more serious warts with time as the project goals have shifted in very large ways, D could be described as boring, useful, and mostly keeping up with the trends, which is a pretty decent place for a fundamental software development tool to be in. I'd be happy to use it again.


If LLVM languages are going to become more mainstream in the browser, you need more than a WASM backend - you need to significantly improve interaction with the UI from WASM.

HTML's canvas might be an adequate stop gap, but it really doesn't seem like an acceptable solution in the long term.


Wouldn't the ultimate irony be "native" toolkits like Gtk and Qt being normalized through WASM code rendering to a canvas?


Qt already supports WASM, [0] but it's a long way from being 'web native'.

[0] https://www.qt.io/qt-examples-for-webassembly


This is one I really like

https://p0nce.github.io/d-idioms/#Parallel-foreach

I use D as a complement to R. If I'm doing a simulation, it's really simple to shift to doing them in parallel. (I know other languages also provide such support, but I'm a fan of the overall D language as a replacement for C in the statistical computing realm.)


D is really really nice for writing code then upping the performance as you go.

We do need better scientific programming libraries, however.


> ** is really really nice for writing code then upping the performance as you go.

We do need better scientific programming libraries, however.

This is pretty much a rephrasing to few of the main goals of Julia. You start prototyping using the dynamic python/lispy, and add some typing or some optimization to got C/Fortran performance. It is really finding it's space in scientific computing. Check out Flux.jl, DifferentialEquations.jl, and SciML.jl for a preview of the cool projects Dynamic Dispatch is enabling.

Bonus points for excellent Macros: MLstyle.jl


Put it this way, I am using D quite a lot for microarchitectural benchmarking because the inline asm is so easy to us, I have access to LLVM and GCC intrinsics, I can easily parameterize my code as a template at compile time etc.

Julia has impressive libraries, I don't really rate the language.

D gives more guarantees to the optimizer, makes it easy to give information to said optimizer and has much safer slices which prevent a lot of bugs.

For example of something cool: I have a library which can run a benchmark over a template - that is, imagine a template taking a parameter N or even a type, my library can iterate through these and perform statistics on them seamlessly.


Yep, I often hear people say their favourite language would be great for scientific programming, it only needs scientific libraries and people to use them. Julia already has those things, they're not easy to get.


We already have a library called Mir which has laid down a lot of the hard stuff to begin with. Its very very fast even relative to the small number of people working on it.


I agree. I have everything I need after 7-8 years, but that's not true for everyone.


We're using Go for our discrete sim as well as our optimization platform and I love it.

A lot of these samples of D are really enticing and I think I'm going to have to spend some time really digging in. I hope the toolchain is nice.


For an introduction to the language try tour.dlang.org

Also, feel free to ask questions about the language (I work for the D foundation).


Remember to add the https to make it clicky https://tour.dlang.org/


Would you recommend D for web APIs?

How fast is D compiler on a 100k line project?

Does it support incremental compilation?

How's the package management story and where is D heading in this camp?

Thanks!


> Would you recommend D for web APIs?

vibe.d is quite good

> How fast is D compiler on a 100k line project?

The D reference compiler takes a few seconds on my machine and is about 450k lines.

> Does it support incremental compilation?

Not very well if at all.

> How's the package management story and where is D heading in this camp?

Uninspiring but more than enough to be productive - i.e. infinitely better than C++


> How fast is D compiler on a 100k line project?

On Apple M1, a full rebuild of one of my product (approx. 80kloc) is 6 seconds. 1 seconds incremental.


> How fast is D compiler on a 100k line project?

I have a 140k line multi-purpose library that compiles in 2 1/2 seconds on my i5 computer w/ ssd. But this varies very heavily depending on what language features you use (compile time execution of functions can make a 3 line program compile in many minutes, or simple C-style code can compile 100k lines in a fraction of a second). So don't generalize too fast!

Re web APIs, I've been doing serving and consuming with D for a long time now, I like it a lot. Using some of the compile time reflection stuff is really cool. Like this little demo site: http://arsdnet.net/cgi-bin/survey/record-survey has this source code:

``` import arsd.cgi; import arsd.dom; import arsd.jsvar;

struct Survey { string thisIsFakeDontSpendRealTimeOnIt; string whyD; int yearsUsingD; string[] thingsYouWantMost; }

struct AboutYou { string yourName;

}

class Site : WebObject { @AutomaticForm auto recordSurvey(/* @Flatten */ @DisplayName("") Survey s, @DisplayName("") AboutYou y) { struct Result { string message; Survey surveyAnswers; AboutYou aboutYou; } return Result("Thank you!", s, y); }

// you can also specify things on functions @(Cgi.RequestMethod.GET) @DefaultFormat("json") int giveMeJson(int a) { return a; }

// or have plain boring ones string hello() { return "hello, world!"; }

@UrlName("different-url") string[] anyName(string other) { return ["Hello", "Friends", other]; } }

void handler(Cgi cgi) { cgi.dispatcher!( "/".serveApi!Site ); }

mixin GenericMain!handler; ```

The form is generated from function params, the html from return values, etc. OR you can do json too of course http://arsdnet.net/cgi-bin/survey/different-url?format=json&...

so it is nice. On the client side, I also generate some code so the usage looks like

``` var result = gitlab.rest.users[myuid].pull_requests.GET; ```

and similar so it generates all those things as it needs it (the url made from the dot members, the return value just a dynamic dype). Not like perfect but plenty convenient.


D can compile your entire 140KSLOC project faster than Rust, TypeScript, or C++ can compile a single file. (The lexer has tricks like skipping multiple spaces at once in order to achieve this.) So, there isn't really a need for incremental compilation yet.


It depends on the style of code. In both C++ and D world, code with many template instantiation builds slower.


HN code-ifies text if it's indented after a newline


I'll be honest, D looks like a pretty inconsistent language. It has a lot of useful features for sure, but—having not used it—seemingly of the kitchen sink variety.


With D it is unnecessary to build projects out of multiple languages, as D supports conventional C type programming, template metaprogramming, OOP, and functional style. (It even has an inline assembler for metal style!)

Each of those paradigms has its place, and I enjoy being able to mix and match them as appropriate in the same program.


You can even use opDispatch to generate methods or values of a class at compile time based on the name, Python __getitem__/JavaScript Proxy/Ruby style.


That kind of sounds like a worse Common Lisp.


Its definitely of the kitchen sink variety. I don't think that's a bad thing though. D is a toolbox with a ton of tools in it. You might not need them all, but its nice that they're there when you do need them.

You're not forced to use the features you don't need.


That's also what C++ is, but surprisingly people like to hate it for that, too :/


Consistently pragmatic, is the philosophy, really.

There are some pain points that could probably go but realistically the aim is to make writing efficient code easy and abstract code even easier within the same language.

If you learn D you get to avoid a bunch of legalese compared to C++, and lots of runtime bugs compared to Python - there are more features to learn, but they generally make quite a lot of sense when you need them e.g. Ada-style contract programming is extremely useful the moment you don't have it.


Can you point to somewhere which makes the case for D vs C++ as of 2020 or so?

I always had the sense - without seriously looking into it though - that D was about avoiding some of the mistakes/mis-features of C++, but C++ is always getting new stuff, which doesn't sit exactly well with what D has chosen, and then it plays somewhat clunky catch-up. But I may be very wrong.


> I always had the sense - without seriously looking into it though - that D was about avoiding some of the mistakes/mis-features of C++, [...] and then it plays somewhat clunky catch-up.

My opinion is that D lost its goal on the way. It was indeed supposed to be a cleaner C++ without all its confusing history of layers of features over layer of features. And it was so, for sometime. But then they started adding this, and this, and that, everything and all sorts of kitchen sinks depending on the fad of the year; meta-programming, taking from C++, or lately rustifying itself. The current state looks to me is as indigestible as modern C++ (and the process to get there has largely been the same, the process the original goal of D meant to rid and avoid). A pile of templates and annotations. D's evolution has been a great disappointment to me. I can see Nim going that way too.


But, you know, C++ can't be seen as a proper, complete language as it stood in 1998. A lot of it was partial scaffolding for future development of the language. In order to clean it, you either had to fill in the missing 25-years-or-so of C++ features (in some form or another), or settle on a much more limited language.


It certainly looks very complex and feature heavy.


C++ has improved a lot, but many of those solutions have been half-assed versions of things D does to completion.

CTFE in D works as you would expect, constexpr is a weird hack.

Concepts in C++ are ridiculously overcomplicated and are done with a much simpler solution in D.

Ranges are also much better thought out in D.

C++ will also never replicate D's ease of use when it comes to metaprogramming - static foreach and if for example have no alternative in C++ (if constexpr is incredibly stupid)


So, you're saying: CTFEs, concepts and ranges done right. Hmm. Sounds good, actually...


https://run.dlang.io/is/dkFWTu

Sink your teeth into that. Code generation at compile time, functional programming etc.

The compiler can actually check that this is pure for you but in this case it isn't performed so it can read from stdin


D doesn't have concepts. It just takes a different approach.


> if constexpr is incredibly stupid

Would you care to elaborate what's wrong with it? When I used it I always felt it was quite straightforward.


D CTFE restricts what you can't do. If I write my own vector type, even with my own malloc (it would have to get it's memory from the GC when running under CTFE for obvious reasons, but still), I can do useful work on it at compile time and then save that result in the data segment of my executable.

Constexpr tells you what you can do. It adds huge amounts of bulk to the standard, there is syntax soup everywhere now etc.


Yes, C++ has been catching up since C++11.

One thing C++ will never have is D's `static if`, which allows injecting declarations into scopes. Bjarne Stroustrup and others closed that door: https://isocpp.org/files/papers/n3613.pdf


> One thing C++ will never have is D's `static if`, which allows injecting declarations into scope

don't be so sure

https://github.com/lock3/meta/wiki/Metaprogramming-Introduct...

a lot of it is already implemented: https://cppx.godbolt.org/z/4arx6T


Thanks for letting me know. This seems to be far from being adopted into C++, if at all, right? Is the C++ community behind this effort?


It has been proposed by Herb Sutter a few years ago and has been worked on since by Andrew Dutton, so yes the c++ community is definitely behind it.

See e.g. https://youtu.be/8c6BAQcYF_E


Seems horrifically complicated?


it allows to generate code at basically every scope and to create your own "base language elements" like "struct", "class". AFAIK D does not allow for this, does it ?


D's templates has always been very strong and useful compared to C++'s.

The following example is similar to C macros because it generates code as string and mixes it in as code but you can combine templates as well. This example generates a struct definition.

(Edit: formatting)

  import std; // Entire package for brevity
  
  auto memberDef(string type, string name) {
    return format!"  %s %s;"(type, name);
  }
  
  auto memberDefs(string[] members...) {
    return (members
            .chunks(2)
            .map!(pair => memberDef(pair[0], pair[1])));
  }
  
  auto structDef(string name, string[] members...) {
    return format!q{
      struct %s {
        %-(%s%)
      }
    }(name, memberDefs(members));
  }
  
  unittest {
    mixin (structDef("Foo", "int", "i", "double", "d"));
    auto f = Foo(42, 1.5);
    assert((f.i == 42) && (f.d == 1.5));
  }
  
  void main() {
  }


Sounds like something `if constexpr ()` comes close to


C++ doesn't implement the D features right.

For example C++20 has constexpr, consteval, constinit, for a less powerful equivalent of D's CTFE.

D use no syntax for this. Things are evaluated in CTFE when they can. The rules are simple, and you can ignore them for the first few years. It's because CTFE is considered a normal thing in D.


This is great! All languages should provide an idioms page on their website.


Good to see D getting some acknowledgement now and again! I haven't touched it in a while, but have a soft place in my heart for it.

Features I absolutely love that I wish I could use at work (stuck in C++98 land, slowly upgrading) include ranges, template metaprogramming, and inout. So much of the surrounding toolset could be removed if only I had those capabilities.




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: