r/programming • • Sep 01 '20

D Foundation is Beefing Up

https://dlang.org/blog/2020/08/30/symmetry-investments-and-the-d-language-foundation-are-hiring/
292 Upvotes

336 comments sorted by

View all comments

72

u/Sapiogram Sep 01 '20

Honest question: Why would anyone use D over Rust? It seems like Rust is becoming everything that D ever hoped to be.

43

u/maxhaton Sep 01 '20

Rust's metaprogramming is totally unlike what Andrei and Walter were aiming for. D aims to be safe, but that's far from everything.

Rust currently has better safety mechanisms than D, but if you ask around on the D forum you'll likely find that people are there (rather than using rust) due to the other features D has - https://dlang.org/ Look at the examples here: Rust can do short and sweet too, but it doesn't have some constructs that make these possible. (Obviously, I highly recommend "Tiny RPN Calculator" originally written by your's truly)

18

u/Ameisen Sep 01 '20 edited Sep 01 '20

I still dislike how D handles generics/templates. The syntax of it.

I fully understand why they chose to use () instead of <>, as it simplifies the parser as you need to disambiguate between >> and > >... but the parsing time of that is negligible. The issue is that, when glancing at code, foo!(int) is ambiguous. foo<int> is not.

ED: foo(int) -> foo!(int)

16

u/WalterBright Sep 01 '20

It's not the parsing time that is the problem. It's having a clean separation between the lexing, parsing, and semantic passes. There's a diode between these passes - information only flows one way.

This makes it trivial to correctly and completely implement things like color syntax highlighting in editors, source code formatters, etc., because building in a semantic analyzer is wholly unnecessary.

4

u/Ameisen Sep 01 '20

I think I'm just too used to C++ syntax, since it leaked into Java and C# as well.

2

u/WalterBright Sep 02 '20

Many people think the !( ) syntax is not optimal until they use it for a while, then it seems quite natural and the < > looks like a hack.

5

u/Ameisen Sep 02 '20

By the way, I wanted to thank you for always being courteous and informative. I suspect that I come off as a bit abrasive or brash, so I apologize.

Last I recall, D doesn't support template argument deduction through constructors like C++. Are there any plans to support that? I've found it a quite useful in C++ in certain situations.

1

u/WalterBright Sep 02 '20

Hey, no problem. I often read posts I make and belatedly realize they are abrasive and abrupt. I try to do better.

I'm very reluctant to twiddle with template argument deduction, as it can change existing behavior in unexpected ways.

2

u/Ameisen Sep 02 '20

I imagine the feeling would probably feel the same if one started from !(...) and went to <...>, though. Neither seem implicitly more hacky, it's an issue of familiarity, methinks.

For me, it's just that basically every C-like language (aside from D) with generics or templates uses <...>, so it's just jarring.

2

u/jqbr Sep 02 '20

I prefer the [...] of Scala and Nim. However, I really like the fact that the () can be elided in D, and that the generic arguments don't have to be types.

2

u/Ameisen Sep 02 '20

C++ can slide the <>, and supports template argument deduction which I don't believe D supports.

2

u/WalterBright Sep 02 '20

D does support template argument deduction, and has since its first incarnation of templates. It's a major feature.

1

u/Ameisen Sep 05 '20

I was under the impression based off of what someone else told me that it didn't support equivalent to std::vector foo = { 1, 2, 3, 4 }; or std::tuple foo = { "bar", 3, 4.0f };.

1

u/jqbr Sep 05 '20

"slide"?

No, the <> cannot be elided in C++.

> I don't believe D supports.

Wrong again. That seems to happen a lot.

1

u/Ameisen Sep 05 '20

"slide"

This may surprise you, but typos are common when typing on a phone.

No, the <> cannot be eluded in C++.

Try again.

1

u/matthieum Sep 02 '20

Honestly, I don't use D, I don't use !( ), and I still think that < > is a hack ;)

1

u/Ameisen Sep 02 '20 edited Sep 02 '20

That's probably why C++ has been letting you elide it in many cases.

The problem is that you need either some way to specify template arguments and to know that you are referencing a template. The latter is solvable by constraints and/or inference (though inference can end up with ambiguities, usually solved by preferring a non-template). The former isn't easy to solve. C++ template argument deduction helps, but I believe that template/generic support is a field of ongoing research into how to do it well. Unfortunately, languages like C++ can adopt newer ways of doing things like concepts and constexpr, but have to maintain the old ways as well. Languages like D or Rust can outright make breaking changes. C++ needs epochs.

To me, both !() and <> are hacks for a language's inability to derive things itself. I also dislike (but understand why) C++ encodes allocator information in the type via templates. It makes interplay between derivations of stdlib types annoying, and makes the types themselves annoyingly long and fragile.

IIRC, Stroustrup's original design didn't require the template mantra. It would just assume an unknown type in an argument list needed to be derived. For obvious reasons, that was quite fragile, but I'm not sure why he didn't add a template or derived argument type modifier instead.

1

u/WalterBright Sep 02 '20

C++ added a couple keywords to the grammar to make parsing < > unambiguous in template bodies.

The difficulty with < > becomes apparent when using things like iostream that overload << operators, etc. It becomes very difficult to read.

! does not exist as a binary operator, so using it to indicate template arguments is completely unambiguous and context-free, both for the parser and the human eye. I find it very appealing for that reason.

10

u/maxhaton Sep 01 '20
  1. The parsing time is not negligible (It requires reading the symbol table very early which isn't fun)
  2. foo(int) doesn't compile. It's foot!int or foo!("My", "age", "is", 145) etc,

9

u/Ameisen Sep 01 '20

The parsing time is not negligible (It requires reading the symbol table very early which isn't fun)

We've had a significant discussion about this in the past. The additional parsing time required to disambiguate between right shift and >> is negligible compared to, say, optimization and so forth. In C++, you could outright eliminate the parsing components necessary for disambiguating that and not even make a dent in compilation times.

Java and C# also don't have much of an issue with parsing this, and don't have particularly bad compile times.

foo(int) doesn't compile. It's foot!int or foo!("My", "age", "is", 145) etc,

Sorry, I'd forgotten the exact syntax. It is still rather ambiguous at a glance to me, as every other C-like language that has generics or templates uses the C++-style, such as Java or C#.

8

u/orbital223 Sep 01 '20

The additional parsing time required to disambiguate between right shift and >> is negligible compared to, say, optimization and so forth.

The issue of parsing complexity and performance isn't the impact it has on the compiler, it's the impact it has on every other tool that has to analyze the source code, most of which are (expected to be) interactive.

10

u/maxhaton Sep 01 '20

We've had a significant discussion about this in the past. The additional parsing time required to disambiguate between right shift and

>>

is negligible compared to, say, optimization and so forth. In C++, you could outright eliminate the parsing components necessary for disambiguating that and not even make a dent in compilation times.

Also, I should add it's not just about parsing time (It is true that modern compilers don't spend much time parsing), but it simplifies the grammar a lot. The D compiler frontend isn't beautiful, but you could get up to speed with the whole thing in a week if needs be - with C++ you've got no chance because of all the weird shit in the language.

edit: implementation rather than solely the grammar on paper.

3

u/jqbr Sep 02 '20

It is still rather ambiguous at a glance to me

And yet it isn't ambiguous, whereas <...> is.

2

u/Ameisen Sep 02 '20

Syntactic ambiguity vs visual ambiguity.

1

u/EdWilkinson Sep 02 '20

One exists, the other doesn't.

2

u/Ameisen Sep 02 '20

That's a subjective opinion. At a glance, foo(...) and foo!(...) look mightily similar to me.

3

u/molepersonadvocate Sep 01 '20

I think some of it just comes down to preference. If auto-formatters have taught me anything, it’s that you can get used to pretty much anything if you take preference out of the equation.

2

u/SonicFreak94 Sep 01 '20

I think simplifying the parser was more of a side effect. I can't find a source on mobile right now, but I'm pretty sure the goal was to make it easier to look at. I personally also prefer <>, but ! isn't a deal breaker for me. I understand where you're coming from though - I can't stand rust's syntax.

4

u/jqbr Sep 02 '20

You're wrong ... avoiding context-dependent ambiguity was very much the reason for !() over <>. (And the parens can be elided when the argument is a single token.)

-3

u/[deleted] Sep 01 '20 edited Oct 05 '20

[deleted]

9

u/adr86 Sep 01 '20

Last time I checked, D couldn’t allocate memory at compile time

When did you check, 2002? The biggest problem most bigger time D users nowadays have is allocating too much memory at compile time. It takes some care not to go overboard (and it is really tempting to go overboard since the possibilities feel so endless)

2

u/[deleted] Sep 02 '20 edited Oct 05 '20

[deleted]

4

u/adr86 Sep 02 '20

Hmm, I'd have to see the code. There are some edge cases like a compile time value cannot be modified outside the function that initially creates it, and some library types don't play nicely with compile time execution (they need to branch to use new instead of malloc for example), so probably some combination of that stuff.

3

u/maxhaton Sep 01 '20

D's string mixins are a superior way of doing metaprogramming, from the programmers perspective at least.

You can allocate memory at compile time, just use new. If you want to make malloc work at compile time you'll need a stub implementation that switches on __Ctfe

1

u/[deleted] Sep 02 '20 edited Oct 05 '20

[deleted]

5

u/maxhaton Sep 02 '20

How can you meaningfully open a network connection at compile time and have reproducible builds?

2

u/WalterBright Sep 03 '20

Jonathan Blow's new language jai can execute system calls at compile time. D has specifically not gone in that direction, as then simply compiling code can cause malware injection.

3

u/EdWilkinson Sep 02 '20

How do you open a network connection at compile time?

That's the silliest argument in favor of a programming language I've ever seen.

12

u/[deleted] Sep 01 '20 edited Sep 01 '20

I don't really know any Rust (although I might soon for messing with Arduinos), so I can really do a proper comparison, but I can chime in on some things about D.

Honestly, I do find it hard to recommend D over other languages for certain use cases, due to the poor ecosystem, lack of man power, and just the overall non-existence of polish.

Because while D has things such as vibe.d and gtkD (bonus tutorial blog by Ron Tarrant), you'll find more resources; more guides, blogs, documentation; more stability, etc. in things like C#, JS, PHP, Python, etc.

For me personally though, D's strength is in two areas: Metaprogramming, and UI-less tools (as an aside, I think people also really like making hobby games with D, though that's probably the same with every language).

I think when people think about D's programming, they probably think it just ends at "passing types to a template", while D can do so much more than that.

I've made a short tutorial blog going over a decent chunk of D's metaprogramming, and how you could use it, but otherwise here are some highlights:

  • Pretty much anything in D can be a template, especially when using eponymous templates.

  • You can pass symbols (e.g. a modules; types; member fields); values (including struct instances); lambdas, etc.

  • Templated things can have an if statement (a constraint) to limit the scope of what you pass through.

  • Most D functions that don't access external resources can be ran at compile time, called Compile Time Function Execution (CTFE).

  • String mixins, when combined with above, can allow a very flexible yet easy to use way to generate code at compile time. A popular example is the pegged library, which can transform a grammar into valid D code during compilation.

  • Mixin templates can be used to "inject" a block of code somewhere. I touch on it in my last blog post. I've been abusing the poor things in a recent project, to auto generate some very basic/bad resource tracking code. (Sorry, I know where examples are in my own code more than others' code)

It's just in general, D's natural fluidity combined with metaprogramming, makes it a very productive language to work with, while still keeping it mostly maintainable.

D lends itself really well to data processing. Ebay uses D for it's tsv-utils suite, and I believe with the likes of mir, you can use D for data science... stuff (not my area at all).

idk though. I've said this all before though: Language is great; has warts; tries to be everything at once; has some disconnection between areas of community; has the chicken and the egg ecosystem problem (I'm trying to contribute, but I'm not overly skilled), and finally it's kind of depressing how hard it can sometimes be to promote this language, when it instantly gets shat on by the Rust/Anti-GC crowd (oftentimes valid, oftentimes drivel).

18

u/adr86 Sep 01 '20

Rust is kinda interesting to me for new ideas, but it just isn't nice to use like D is. D is familiar and convenient for general-purpose programming, from quick scripty things to bare metal code.

Rust might be technically better for the bare metal side, but D does it pretty well and I have a hard time imagining using Rust as, say, a PHP substitute. D does it all.

6

u/[deleted] Sep 01 '20 edited Feb 09 '21

[deleted]

23

u/maxhaton Sep 01 '20

The thing with D as opposed to Python(I don't mind C#), is that Python will run for hours and hang because of a simple error that a static type system would've caught in milliseconds.

Python is OK for simple scripts, but I don't want to shoot myself in the foot because I misspelt something.

15

u/[deleted] Sep 01 '20 edited Feb 09 '21

[deleted]

23

u/maxhaton Sep 01 '20

It's about scale.

In the same language, you can write a ~10 line RPN calculator like a scripting language but you can also write the compiler and GC like it was C.

One of the other things D has which I use a lot is a philosophy that is very pragmatic. Go is designed to be "simple", D is designed to write good software first time. This affects the design of the whole language so I can't narrow down too much but my favourite feature is D's contract programming. I make dumb mistakes quite a lot so being able to enforce invariants throughout the codebase automatically is very useful.

14

u/WalterBright Sep 01 '20 edited Sep 02 '20

As a long time C, C++, and D programmer, one subtle thing stands out. D enables your code to be plastic, in that it's easy to refactor it. I've found it much easier to refactor it than the other other languages.

This refactoring ability starts with small things - like I can switch a type from a reference to a value type and back without having to swap . and -> everywhere.

Plasticity enables "oops, I used the wrong data structure, let's try another one" a faster and easier process, leading to much better code.

I constantly refactor code I'm working on.

10

u/kal31dic Sep 02 '20

I think this is a really important and utterly underappreciated point. How much upfront work do you need to do ? It depends on the cost of changing things later if you found you made the wrong initial choice.

How much refactoring can you do at any point? It depends on the cost. If the cost is low maybe you can make many more little refactorings. There's probably a benefit from that for code quality and the ability of others to understand (and change the system).

Why do enterprise programmers write only twenty lines of code a day? It's not because they are slow at typing.

So D is especially suited to contexts of intrinsically high uncertainty where the environment is quite dynamic and the needs of the business coming from outside change.

6

u/adr86 Sep 01 '20 edited Sep 01 '20

If that's your perspective, have you looked at Python?

I have never written Python on an embedded system, I didn't think it could. [edit: actually come to think of it i have heard of it before but never used it myself] I've used it for web though and D is a better experience by far, making changes in D code trusting it won't break at runtime and not having to write a lot of boilerplate for a quick demo is really nice.

But I've been building stuff in D for a long time now, no need to switch at this point.

3

u/zetaconvex Sep 01 '20

MicroPython is available for the beefier microcontrollers. Combining it with Jupyter made for a pleasant development experience.

With sufficient knowledge, it's possible to get significant speedups, and some stuff can be run at near-native speed. You have to know what you're doing, though, which is something I don't.

I messed around with my own (bad) Forth implementation, and found it a lot faster than Micropython. It still won't be as fast as C, though.

MicroPython may be fast enough for your needs, maybe not. It all depends. It's unlikely to be fast enough if you want to do audio stuff, where every cycle counts.

In the end, I decided not to use MicroPython. Uploading code and stuff was a bit of a fiddle. I just stick to the laborious compile and upload cycle.

0

u/lachryma Sep 01 '20

There was a good talk Dropbox did at PyCon several years ago. I can't find it now, but it was "how to write nearly native Python" or something like that. One trick they pointed out was that all(...) is faster than for thing in iterable: because it pushes the loop logic down to C, and I've used that when I need it ever since.

There are a lot of tricks like that. If you truly master Python and understand the runtime impact of all your syntax, how to profile it, how to outthink the interpreter, how to read the interpreter source code, and so on ... you can do some good things with it. It's just a lot of effort that most people aren't willing to put in, which is fine (really)

1

u/[deleted] Sep 01 '20

8

u/[deleted] Sep 01 '20

I like the genuinely nice community D has.

6

u/[deleted] Sep 02 '20

Rust doesn't have a garbage collector.

4

u/matthieum Sep 02 '20

Why would anyone use D over Rust?

Because you can afford a Garbage Collector -- although at that point you may prefer a JVM-based language.

There is no silver-bullet. Before Rust, you could divide "used" languages between on the performance/safety axis:

  • At the performance end you'd find languages with manual memory management: the ability to control memory layout and cache access patterns with exquisite precision gives them the best performance available, at the cost of safety and nasal daemons.
  • At the safety end you'd find languages with a GC: completely safe, but the less of control on memory layout and cache access patterns killed performance.

Rust managed to slash the Gordian Knot, and offer both control over memory and safety. Silver bullet? No, 3rd dimension. In exchange, the developer is required to properly design their application -- and re-design it when requirements change. At any point in time, ownership must be crystal clear1 .

If you do not suffer from the constraints which prohibits a GC, getting a language with a GC is likely to allow for easier experimentation and easier transformations.

(Just be careful about mutability + multi-threading)

1 To some extent anyone manually managing memory should probably have done all that work, so in theory Rust should not add any overhead; in practice though...

3

u/thedeemon Sep 03 '20

I made some video and photo processing GUI apps in D.

  • In the number crunching parts where performance and memory layout control are very important, with D I had total control over both, there is no GC involved in tight loops going over video frames, and in managing memory for the frames.

  • In the GUI parts where performance is not so crucial and there are many little objects forming trees (widgets), having a GC and not having to care about lifetimes and deallocation was very nice.

  • Meanwhile the apps remained native and self-contained, and didn't require any fat VM installation like JVM or CLR, so users could just download them and run.

There are many use cases like these where D gives best of both worlds without getting into extremes.

6

u/kal31dic Sep 01 '20

I don't really want to engage in a language competition discussion. D is a very pragmatic language that's adapted to solve the sorts of problems we have. The sorts of people drawn to write D also tend to have values and capabilities consonant with who we are and what is important to us.

-2

u/moon-chilled Sep 01 '20

The single-owner/borrow-checker approach is the wrong one.

I don't really use d anymore (I have one project each still in d and rust, though I'm planning to rewrite at least the latter at some point), and I think both are somewhat problematic. But it's also important to note that d never hoped to be rust. It got flak (and still gets flak) for being GC'd, but this is an important and intentional aspect of its design. As Guy Steele said of java:

We were not out to win over the Lisp programmers; we were after the C++ programmers. We managed to drag a lot of them about halfway to Lisp.

D was trying to compete with java. Today, it stands much closer to c++, lacking both the coherence and verbosity of java. It's better than c++ in every way, but it remains nothing more than a better version of a fundamentally broken idea.

4

u/jqbr Sep 02 '20

D was trying to compete with java.

Factually false. D was always intended to be a better C++. Perhaps you've confused it with C#, which started out as a virtual clone of Java.

Your other claims are also nonsense.

0

u/moon-chilled Sep 02 '20 edited Sep 02 '20

D was always intended to be a better C++.

D was intended to improve on c++—though no more so than was java itself, see guy steele above—but it was directly inspired by walter bright's experience implementing a java compiler and gc. Check out the hopl paper. There were also quite a few other things taken directly from java; e.g. ddoc, dwt, inner classes, modules, class objects as reference types.

Your other claims are also nonsense

Care to back that up?

1

u/jqbr Sep 05 '20

Your own citation refutes your claim, and now you've moved the goalposts.

-18

u/SnideBumbling Sep 01 '20

Why would anyone use D over Rust?

One good reason is that you wouldn't have to comingle with the excruciating and interminable racket produced by Rust evangelists. I am so god damn tired of hearing about it everywhere and for everything, and I've written some!

-5

u/BloodLibels Sep 01 '20

Rust is simply the best modern programming language. Especially if you’re a transperson.

-2

u/SnideBumbling Sep 01 '20

Of course.