Introduction to Dlang [video]
youtube.com
youtube.com
1. I found D pretty easy to learn and use so getting productive in it was easier for me than Rust.
2. D has a lot of improvements to C++ that make it more ergonomic (no header files! built in package management!)
3. D has a lot of flexibility to go up and down the stack in complexity as well as interface with existing c/c++ code.
a. Need to use d for scripting like Python? use Rdmd
b. Need to interface with c code and can't depend on the D compiler? use -betterC ^1
c. Need a quick and dirty way to use C code without creating bindings? use importC
d. Can't use the garbage collector? use @nogc
e. Need to interface with C++? use extern (C++)
D's flexibility is its greatest strength and weakness. It can do a lot of things but not all of its features are ergonomic. A lot of that just has to do with man power. If it had a community as large as C++ things would be different. Using the examples in 3, you could use Ds features and write a kernel with @nogc, a user interface for that kernel using regular D, and create build scripts using rdmd.To see a c++ person perspective on D watch this video^2
1. https://wiki.dlang.org/D_on_esp32/esp8266(llvm-xtensa%2Bldc)...
2. DConf '22: Ray Tracing in (Less Than) One Weekend with DLang -- Mike Shah https://www.youtube.com/watch?v=nCIB8df7q2g
Keep in mind that Rust 1.0 was released in early 2015, and it's not like they were making major changes right up to that release date. I haven't followed it recently, but I doubt it was meaningfully different from the 1.0 release in terms of learning curve.
Here's a blog post from the same year that proposed removing the garbage collector.
https://pcwalton.github.io/_posts/2013-06-02-removing-garbag...
Also, since 2018 with non-lexical lifetimes and some nice error handling improvements, Rust now tends to be more friendly/ergonomic than 1.0.
What's D been doing meanwhile? D community and the authors know its short comings for over a decade now, which are the reasons for its lack of adoption even in the open source world. Most of the D code is yet to be written, tbh. If D can't break stuff to fix the mistakes with defaults, why was all the hatred marketing towards C++? Was it a failed strategy trying to kill C++, so let's just surrender to it via core.stdcpp?
PS: Yes, D has the best interop with C++ in the world and even better interop with C as the memory model is same!
D's advantage over Rust is its familiar syntax and semantics. C, C++, Java, C#, Python, etc. programmers feel at home once they learn some differences. I heard others say "D is what C++ should have been" and "Compiled Python".
I did use Rust for a brief period in a project where the experienced Rust programmer among us was throwing '&' characters here and there to make the code compile, seemingly randomly in many cases. Personally, I remember fighting with impedance issues with the many different string types of Rust. All of this spells a steeper learning curve to me.
I think D is familiar to programmers of many other languages.
It's because Rust gives very low-level control over strings. If what you want is a string the same way as they work in other languages, including D, then use String. If you want very fine control over memory allocation or want the string to be fixed length, then you use a type that guarantees those properties.
String will work with anything, at the cost of having little control over its allocation or representation.
const(char)[]
meaning you can treat it like any other array.https://dlang.org/phobos/std_utf.html#.byUTF
"Throws: UTFException if invalid UTF sequence and useReplacementDchar is set to UseReplacementDchar.yes"
My guess is that this is a mistake and should instead say UseReplacementDchar.no since it makes sense to throw an exception if you can't use U+FFFD here, rather than do both.
Anyway, in my view this is bad the same way the Billion Dollar Mistake is bad, and Rust made the right choice here. Arrays of stuff are great, but they aren't strings. Having to sprinkle "or maybe not" cases all over these libraries because of course these might not really be strings, results in exception fatigue from your developers, which in turn results in lower quality software and more effort for the conscientious developers who stick it out.
D's strings are less stupid than C's (and thus some of the C++ strings) but they're still just arrays which are maybe but maybe not actually text.
Having string be a magic builtin type does not eliminate the problem of dealing with invalid UTF sequences.
Invalid UTF sequences are inherent to the Unicode design, and programmers are left on their own to deal with it. The options are:
1. ignore them
2. use the replacement char
3. throw an exception (or other error indication)
D enables the programmer to pick which they need, on a case by case basis.
#23405 was resolved as fixed a week ago. It isn't fixed. I guess at least I didn't waste my time filing the bug.
If you have type safety, you can make the choice just once.
Rust's String::from_{utf8,utf16}_lossy turn valid UTF-8/16 sequences into strings, and "fix" invalid ones with U+FFFD
Meanwhile String::from_{utf8,utf16} attempt the same but with an Err instead of replacement on failure if that's what the programmer wants.
Imagine if all D's numeric functions took the same attitude as its string functions, insisting on being passed arrays of bytes so that each function can parse those bytes, decide if this is actually a 16-bit unsigned integer (for example) and if so do what's expected otherwise perhaps return an error. We'd spot right away that this was not a practical design.
D's choices here are conventional, but I've come to expect a lot more and so I'm disappointed when I can't have it.
On the other hand, D's dstrings are more like text because they are not only UTF-32 but also random-accessible code points. (D does not address multiple representations of graphemes at language level. For example, at language level, ğ is different from "g and combining breve" but there are std.uni and std.utf modules that help.)
Bytes. It's an array of bytes. D's char type isn't actually restricted to UTF-8 code units, char x = '\xFF'; works just fine even though that's not UTF-8.
From memory running unit tests printed some weird error, which everyone just ignores. Also importC isn't what you think it is - it's for statically compiling C files in your source directory, not importing foreign C libs you've installed on your system.
I definitely think there's a place for a GC'd, memory efficient, natively compiled language. I just wish after all these years it felt mature.
I am not aware of a common issue like that but D has bugs.
> Also importC isn't what you think it is
That's contrary to my tests: I installed libplot on my system, 'import'ed its .h file to my D source code, called C functions from D, linked with -L-lplot and it worked.
> not importing foreign C libs you've installed on your system
Maybe you mean something else with "importing" but I installed a foreign C library on my system and it just worked without any hand-written D bindings for it.
Not an error I suppose, but doesn't fill me with confidence nonetheless.
$ dub test No source files found in configuration 'library'. Falling back to "dub -b unittest". Performing "unittest" build using /home/lewis/dlang/dmd-2.100.2/linux/bin64/dmd for x86_64. myproject ~master: building configuration "application"... Linking... Running myproject Hello world! (dmd-2.100.2)[lewis@lightgrey myproject]$ micro source/app.d (dmd-2.100.2)[lewis@lightgrey myproject]$ dub test No source files found in configuration 'library'. Falling back to "dub -b unittest". Performing "unittest" build using /home/lewis/dlang/dmd-2.100.2/linux/bin64/dmd for x86_64. myproject ~master: building configuration "application"... Linking... Running myproject core.exception.AssertError@source/app.d(9): unittest failure ---------------- ??:? _d_unittestp [0x555fe0e339b1] source/app.d:9 void app.__unittest_L8_C1() [0x555fe0e328b8] ??:? void app.__modtest() [0x555fe0e33888] ??:? int core.runtime.runModuleUnitTests().__foreachbody6(object.ModuleInfo) [0x555fe0e3d9c2] ??:? int object.ModuleInfo.opApply(scope int delegate(object.ModuleInfo)).__lambda2(immutable(object.ModuleInfo)) [0x555fe0e3b88f] ??:? int rt.minfo.moduleinfos_apply(scope int delegate(immutable(object.ModuleInfo))).__foreachbody2(ref rt.sections_elf_shared.DSO) [0x555fe0e42a83] ??:? int rt.sections_elf_shared.DSO.opApply(scope int delegate(ref rt.sections_elf_shared.DSO)) [0x555fe0e42f5b] ??:? int rt.minfo.moduleinfos_apply(scope int delegate(immutable(object.ModuleInfo))) [0x555fe0e42a11] ??:? int object.ModuleInfo.opApply(scope int delegate(object.ModuleInfo)) [0x555fe0e3b861] ??:? runModuleUnitTests [0x555fe0e3d80e] ??:? void rt.dmain2._d_run_main2(char[][], ulong, extern (C) int function(char[][])).runAll() [0x555fe0e342d8] ??:? void rt.dmain2._d_run_main2(char[][], ulong, extern (C) int function(char[][])).tryExec(scope void delegate()) [0x555fe0e34265] ??:? _d_run_main2 [0x555fe0e341ce] ??:? _d_run_main [0x555fe0e33f97] /home/lewis/dlang/dmd-2.100.2/linux/bin64/../../src/druntime/import/core/internal/entrypoint.d:29 main [0x555fe0e328dd] ??:? __libc_start_main [0x7f1a0be25e09] ../sysdeps/x86_64/start.S:120 _start [0x555fe0e327c9] 1/1 modules FAILED unittests Program exited with code 1
If the default project manager barfs out all of that - ??? and all - when you write a simple hello world project with a failing test...
Well I'm not filled with confidence. If you discover such a lack of care at that early of a stage, god knows what it'll be like when you actually start solving problems.
Do you have a view on OCaml?
Every value needs to be tagged, so an `int` only has 31 bits of numeric information.
There's stuff like "Int32.t", but IIRC it takes up 8 bytes for 4 bytes of inty goodness. Then there's BigArray which can store them contiguously, but that doesn't carry over to records.
But I still look forward to D having its place as well.
1. It have no edge, its not the best system language, and far from a good application language (mainly because of the eco system)
2. Fragile community, low number of user and the community forum is toxic frequently
3. It doesnt have strong leadership, D doesnt have a good roadmap, and constantly changing vision
4. Its a big language, and considering the drawbacks, its too big to have such critical drawbacks
I cant really think of any solid reason, why anyone would invest in D, except if they are already knee deep into it for some historical reasons
D is not a horrible language, but today there are so many better choices, and the language is too big, to risk investing in it
I don't know what the word "toxic" means in your sentence, but anyhow the D forums are one of my favourite websites on the internet:
https://forum.dlang.org/group/general
Heck, I'm not even interested in the D language too much, but these forums are so good that I browse them in awe at least once per week. They are so responsive! I'm not even talking about the contents, but about the website itself. An arrogantly efficient showcase of what a good website can be.
Shit languages with "good" ecosystems are still shit. They're crap. Once you have the library you want, you're still mercy to bad language design.
and if i may guess, whatever you are building, this is not a new company and not a new product, probably something that started between 2000-2005 if not even before
"sell me F# meme", what is that, F# is one of my favorite languages, I like a lot OCaml and languages similar to it
what exactly does this mean?
We do our best to ensure everyone feels welcome to join in. Of course none of us have social media training and are just doing our best.
If something is going down and we are not taking action it may be because we are not aware of it being problematic and are always open to hearing complaints as they come up!
Side Note: Why don’t I ever hear about Nim anymore??? It’s version 1.68 (and presumably stable), has very approachable syntax, claims great performance, provides a package manager, and allows the GC to be turned off (much like Dlang). What gives?
Nim has some serious technical debt, and it seems they don't have the manpower for it:
This is just to pick on your example. There is surely much other technical debt in the compiler itself. The solution to low manpower, if you otherwise like Nim (or D), is to try to help the open source effort at whatever level you can: do your own packages, tutorials/documentation, etc.
I don't know if it's still the case. But there were issues with Nim executables being incorrectly flagged as viruses in Windows. ^1
That's what the interoperability is for!
For history, I hated D back in 2006/7. But post Andrei joining D was fantastic. It was very easy to jump into D's standard library and understand it's inner workings. Over those years I created and maintained apps, services and microservices written in D. It was pleasure writing programs in D. Its compile time features make it pleasurable to write algorithms and refactor at ease.
But it was horribly painful to debug production issues. GC crashes day in and day out. Missing ecosystem of libraries and tools. vibe-d was unstable, so we had to create our own HTTP2 library. There's very little tooling to figure out what's going on when things go wrong. Templates in D are awesome for compile time, but it's the opposite case with GC and runtime.
D's built in attributes are like family members who don't like each other but are trying to live in a single room. What else do you expect of such programs? You try to observe/log from your transport layer, but when you get deep into BetterC layer, you can't use loggers as they use GC. OK, write your own nogc logger, but that doesn't work well with default logger. The cycle repeats for every single attribute and every single behavior during runtime. It's just a mess.
Until I read the source code of Rust standard library a year or so ago. It was not as pleasant as D, but it was easy to understand and pickup the language.
I switched jobs a year ago and instructed our teams to experiment with Rust even though I had decades of expertise with C++ and a decade with D. The immediate benefit we saw was Rust's opinionated error handling, which proved to be the right approach to most of common programming mistakes. We started using Tokio and all praises to it. No going back!
Personally, I can ask my teams to use D when it has all the sane defaults of Rust and a good ecosystem. Otherwise it is way too expensive to maintain as there's no benefit of portability as well. We now write all code in Rust and ship it across different platforms seamlessly, including Android, iOS, Windows, Linux and macOS. One language and code to rule them all.
Few recommendations to @WalterBright as he is on HN.
Personal recommendations: 1. You created D because you felt the pain of the C++ programmers. Appreciate it and thank you for that. Over the years you've built up "the curse of knowledge bias" with D. Start using D as a new programmer to the language and the ecosystem. Come out of your MicroEMACS shell and use a modern editor/IDE like VSCode and see how lacking the tooling is. WebFreak has done an amazing job with code-d[1]. But it is in no competition to Rust's IDE support. 2. Use all the features of D in a non-compiler, long running, real life ML/microservices project. You will see the pains of GC. 3. Unit testing != assert 4. Scoped exit != RAII
General recommendation: SWITCH TO SANE DEFAULTS! 1. @safe by default. Allow hiding all C interfaces under @unsafe. Retire once for all @trusted/@system. @safe => @unsafe 2. BetterC by default 3. Immutable/const by default 4. @nogc by default. That is @nogc => @gc 5. Rust like opinionated error handling and remove exceptions. At least make nothrow default and introduce throw. 7. Reduce the attribute bloat: https://dlang.org/spec/attribute.html
Feedback to D community from learnings in Rust community: 1. Learn to work on team projects to improve D ecosystem instead of shitty ideas about "Signatures", etc. 2. DIP1000 for safety is open for like 7 years and has no conclusion and still NOBODY cares. Just saying that D is alive and community is awesome are just a jokes. D has lost it's "brains" and there are just a few hanging around at the moment, unfortunately. 3. There's not even a standard dfmt template for Phobos/Druntime. Bring one and you will possibly gain contributors.
Yes, Rust code doesn't look elegant with littered angle brackets and &' across the code base, no templates, makes programmers life difficult, etc. But we can live with all that and still have peaceful nights (and weekends) without calls from production support, when compared to downtimes due to half baked features in D (I didn't mention about @live in preview yet).
In the end, a language is not great/usable by itself (that's why there's no money in writing programming languages), but by it's rich ecosystems and community. D was created for novice programmers originally (as programmer's language), but the idea is long dead. It is a mess at this point. You need to be a seasoned/experienced programmer to even maintain a large code base. Using D itself is a code smell, IMHO.
Sorry for venting out, I was the one who recommended D at my past workplace and I was just frustrated my decision and it's consequences.
[1] https://marketplace.visualstudio.com/items?itemName=webfreak...
Criticism is right on point. I believe if you use D in a team, you need to be extra careful to keep the same subset, and also using D is way nicer if you avoid unproven features. To be happy with D you need the utmost restraint with features, and yes unittest helps a lot.
> GC crashes day in and day out.
Sounds like the old destruction ordering problem, and that can be solved by detecting accidental correctness. The problem is destructors called from GC. If you use the GC, you will probably need deterministic destruction in production code, and there are of course ways to achieve it systematically.
> Using D itself is a code smell, IMHO.
I don't see it as more risky than any other language. Especially as the langage is slow-moving, and you don't have to re-learn every 3 years. Large codebase in any language becomes unwieldly. Let's reflect on your next decade of Rust once it's achieved :)
I don't know Zig yet.
I had an opinion long time ago that nobody should use C anymore; I would suggest C++ at least because it has constructors and templates. D's [Better C](https://dlang.org/spec/betterc.html) would be my go-to at this time.
C++ is getting better but it's still very difficult to get right: It depends mainly on programmer attention e.g. to follow 400+ [guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines).
Rust is "different" but it has the borrow checker as a safety tool. D's [live functions](https://dlang.org/spec/ob.html) and other [memory safety](https://dlang.org/blog/2022/10/08/dip1000-memory-safety-in-a...) features are closing the gap there.
> major selling point
I am copying slide 59 here: D provides competitive advantage by helping happy programmers produce correct programs pragmatically.
Slide 8 lists what D does not have, which can explain why D has not gained popularity that it deserves. For example, nobody can sell D as "Google's language" or "Apple's language".
As I understand it, for safe-by-default to work, either all C libraries would have @trusted D bindings written, or all of them would have to be assumed to be @trusted. Most of the community wanted explicit @trusted annotations, Walter and others favored assuming them to be @trusted (or was it assumed @safe?) was the way to go. So, no safe-by-default at this time. :/
@safe nogc:
auto myFunc() { // do stuff }
struct Blah {}
Whatever attributes you use apply to all code in the lexical scope below the colon.It's useful for structs/classes
struct MyThing {
auto unsafeFunc() {}
@safe:
auto safeFunc1() {}
}D had a lot of momentum in the beginning, but the license around the compiler scared away some people, then there was the whole standard library split with phobos and tango (irrelevant now and has been for over a decade), and from my understanding in the beginning (I wasn't around during that time) Walter added features by request as there wasn't a DIP process yet (D improvement proposals), and some people felt it was unfair. These have all been rectified.
I mean... Modules versus header files, 13 times faster compilation, introspection, unittest, etc. etc. etc. Okay, it's more like death by a thousand cuts but once you produce with D, you can't even touch C++ anymore. I am in that state...
anything safer than C, easier than c++ and rust is interesting.
i will build some code and check out its memory usage and binary size, both are important for embedded.
Don't forget the -betterC compiler switch please. ;)