Rendered at 16:11:16 GMT+0000 (Coordinated Universal Time) with Cloudflare Workers.
WalterBright 16 hours ago [-]
I haven't announced my keynote yet, but it's about various ways of handling errors and their tradeoffs. This has inspired some spirited debate in the D forums! I'm looking forward to engaging with everyone.
gregdaniels421 16 hours ago [-]
Ages ago in C++ there was the hope of having the standard library give more error codes and use error values instead of full exceptions. Zig has some excellent innovations in that direction, any hope of that in D?
Edit: I think it was called "Herbception"s after Herb Sutter, and it really sounded like a good idea to me
WalterBright 16 hours ago [-]
It's been a while since I looked at Zig. I couldn't say anything intelligent about it without some study.
I used to be a big fan of C++ exceptions, but eventually soured on it for various reasons. Here's an article partially addressing it from a while back:
I think there is nothing better than exceptions + RAII for error handling since exceptions cannot be ignored by accident.
I would classify D's scope exit/failure/success as RAII actually, even if D uses a GC.
Sometimes you might not need exceptions and something like std::expected or optional is better.
In my case I use expected for some network APIs since I expect failures to happen out of my control aspart of the flow of my program, but I do not see why I would not use exceptions in many other situations, such as for non-ignorsble errors. I could think of a lack of disk space or some other fatal error thst is not under the control of the program.
If you forget to handle this, the error will cascade.
Also, exceptions do not make the signature of a function change (at least not in C++, Java checked exceptions is different). This means that the plasticity for adding errors at any depth of the call stack augments without bypassing any error silently.
All in all, I would say exceptions should be the main mechanism in normal circumstances and for expected errors you csn use error/result types.
nicoburns 10 hours ago [-]
The worst thing about exceptions is that you can't tell from the type signature of a function whether it might throw one. So you have to hope it's documented, guess at whether try-catch is necessary, or reading through the entire call stack.
I personally much prefer Rust style Result which also can't be ignored, and puts fallibili5y in the function signature.
michaelt 9 hours ago [-]
> The worst thing about exceptions is that you can't tell from the type signature of a function whether it might throw one.
In Java exceptions can be part of a method's declared type information, so handling is checked at compile time and IDEs can display the info.
Unfortunately certain Java missteps made this design unpopular these days. For example, for many years new String(bytes, "UTF-8"); made it mandatory to catch a UnsupportedEncodingException despite the language spec guaranteeing UTF-8 would be available. A later version of Java addressed it, but still...
germandiago 6 hours ago [-]
Or you can assume exceptions can be thrown and capture and log coming from a base class in a centralized place (and probably refine incrementally what to do with each group without dirtying all the logic inside the functions themselves).
For Rust result in C++ you have optional and expected. But they have their own problems, like rewriting function signatures all the way up the stack if you notice an error was possible when adding code.
malcolmgreaves 5 hours ago [-]
But with that design, you’re quite limited in what you can usefully do once you catch that exception.
mgaunard 7 hours ago [-]
Any function can throw an exception unless it is marked noexcept.
Your code shouldn't need to make assumption about whether exception are being thrown or not.
Your mistake is thinking that a function potentially throwing means you need to catch it.
WalterBright 14 hours ago [-]
> I would classify D's scope exit/failure/success as RAII actually, even if D uses a GC.
D's scope exit/failure/success is built on top of RAII and has nothing to do with the GC.
> I would say exceptions should be the main mechanism in normal circumstances and for expected errors you csn use error/result types.
Come to DConf (or watch the live stream) and I hope I can change your mind, or at least challenge your conclusions!
germandiago 12 hours ago [-]
> D's scope exit/failure/success is built on top of RAII and has nothing to do with the GC.
What I meant here (I do not know the mechanism) is that I am aware that D has a GC. This means, correct me if I am wrong, that D does not use destructors (like C++) for scope exit/failure/success, though they are scoped mechanisms (RAII-like).
> Come to DConf (or watch the live stream)
I always follow D (even if I did not use it intensively). I have extremely high respect for you as a language designer and as a technician. Your knowledge is very refined, so I never take your opinions lightly.
Probably one of the most knowledgeable persons in the industry for native language design. However, I am far and cannot attend, so I will definitely watch it.
> or at least challenge your conclusions!
No problem in challenging them. I am always open to do things better. This is just my practical experience as I implement stuff so far.
I currently think exceptions seems like a good default mechanism (apparently at least) compared to alternatives. But I also think other mechanisms have their place and can/should be used even in the same program, just for different things.
All mechanisms have trade-offs. I just talked about defaults from my POV for the kind of software I develop (mostly server-side, some client-side, and not embedded in the extremely constrained sense).
-----------------------------
One question: I tried to use D several times in my career (20 years of C++ experience here, roughly). I found it a lot of fun. I like it better than more "modern languages". I like the plasticity D provides. But I am not sure how it would work if I want to do:
1. backend (server-side mainly, Linux is main platform, x86-64)
2. desktop + android and iOS (being mobile more important than desktop)
3. web assembly (even more important than mobile at this moment, could change).
4. backwards compatibility (heard complaints of versions breaking stuff frequently around).
5. interaction with C++.
I do like D a lot, but the problems I had before were more related to tooling (autocomplete, I use mainly Emacs but did not try for a few years) and toolchain maturity.
It would be ready for all of the above? Also, very very handy would be to wrap C++ code and C code. I saw that D had an ongoing effort for C++ compatibility better than other languages, but I am afraid it could be half-broken. Even if it is, it is documented what works and what does not work? That would help a lot.
Thanks.
WalterBright 9 hours ago [-]
> D does not use destructors (like C++) for scope exit/failure/success
We listened, and cut way back on breaking changes. Now we have editions.
> 5. interaction with C++.
C++ has gotten to the point where it would take another decade of my time to wire in ImportC++. However, if you stick with C++'s C interface when interfacing with D, you should be fine. D will also work with C++ name mangling, but all the complexity of C++ templates and such is just too much.
And thank you for the kind words! I definitely appreciate it.
> I am far and cannot attend, so I will definitely watch it.
Wonderful!
skocznymroczny 9 hours ago [-]
Regarding web assembly, support is limited. There's been several efforts to support WebAssembly in D but they were one man efforts that never got finished and merged to the mainline D. The only support there is in the official D compiler is for the BetterC mode, which is a minimal mode with no garbage collection, no runtime and effectively no standard library. There's been some people doing some interesting projects in it but you have to reimplement a lot of basic stuff such as data structures just to get going and at that point you might wonder why not just use C/C++ instead.
There is a fork of D compiler called OpenD which has some WebAssembly support with garbage collection and standard library. I've used it, it works for the most part, but there's bugs and if you encounter any issues then you're on your own.
gregdaniels421 14 hours ago [-]
> I would classify D's scope exit/failure/success as RAII actually, even if D uses a GC.
It has better than that, but it is a bit clunky compared with C++(just use struct instead of class). You can have proper destructors, but if you have a container you need to be more careful than in C++.
In D exceptions are the default like in C++ and you have to opt out with nothrow or extern(C) or betterC.
Really try some D code in a bigger situation it is 90% good and almost worth using over C++, but if you can't have GC it is a huge pain, but better than C.
WalterBright 12 hours ago [-]
I've never understood why GC would be a huge pain. It makes some things a lot easier, like Compile Time Function Execution.
Also, recently the GC implementation received a big modernization upgrade.
pjmlp 10 hours ago [-]
Value type exceptions went nowhere, because that was yet another paper that was never turned into a proper proposal.
Additionally, Khalil Estell has made an excellent work proving that the way exceptions are currently implemented is not optimal and there is plenty of room for improvement, when someone cares about their implementation.
"Cutting C++ Exception Time by +90%? - Khalil Estell - CppCon 2025"
It was the throwing values proposal. Bjarne was not satisfied with the proposal because it didn't interact well with existing exceptions code.
jeffreygoesto 10 hours ago [-]
I loved the comparison of HerbCeptions with expected in https://m.youtube.com/watch?v=GC4cp4U2f2E, a very insightful easy of looking at that topic and really entertaining, too.
macoovacany 16 hours ago [-]
Going to include the common lisp condition system in the comparison?
WalterBright 16 hours ago [-]
I tried Lithp a couple times, but it never caught on with me. I wouldn't know what the best techniques for Lithp error handling would be.
I can never get past the ugly syntax.
mananaysiempre 7 hours ago [-]
Error handling in Dylan[1] worked mostly the same way, if syntax is truly the issue. I posted a toy implementation in Lua a few years ago as well[2]. In general there’s nothing Lisp-specific about the idea, you just need dynamic scoping, closures that don’t outlive their parents, and a way to unwind the stack.
Standard exception handling is:
- Whenever an error happens, the program puts a description of it into an “exception” object. You go from the innermost dynamic scope to the outermost looking for handlers. Once you find a handler willing to accept that type of exception, you unwind to the point where it was installed then invoke it, passing the exception object.
Condition handling[3] is:
- Whenever an error happens, the program puts a description of it into a “condition” object. You go from the innermost dynamic scope to the outermost looking for handlers. Once you find a condition handler willing to accept that type of condition, you invoke it as a regular callback, without unwinding, passing the condition object.
- The handler then packs up some data into a “restart” object. You go through all the dynamic scopes again (remember that the erroring function is still active). Once you find a restart handling willing to accept this type of restart, you unwind to the point where it was installed then invoke it, passing the restart object.
(I am omitting things outside the happy path: a way for the exception/condition handler to punt, what happens if the condition handler does not invoke a restart, etc.)
As far as the benefits of this two-phase approach, Practical Common Lisp gives an example[4] of a single-record parser that raises an “invalid record” condition, a loop around it that installs a “skip to next record” restart, and finally the caller can make the policy decision on what to do for invalid records.
As another example, Common Lisp signals an “unbound-variable”[5] condition leaving the “use-value” and “store-value” restarts in scope, then the REPL installs a handler that offers them interactively. (My own half-serious example of a DOS abort/retry/fail prompt is in this vein too, chosen mostly because it feels strange that you can’t do it in a conventional exception system.)
would you ever do an SF edition? would be happy to host for you. i do a lot of conferences.
WalterBright 14 hours ago [-]
What's an SF edition?
LorenDB 5 hours ago [-]
I would assume OP is asking if you would attend a DConf in San Francisco.
By the way, big fan of D even though I don't get to use it much. Appreciate your work!
bayesnet 13 hours ago [-]
What’s the status of the OpenD fork?[0] I see Adam is still active there but I’m not sure if it’s had any impact beyond losing him as an upstream contributor.
Upstream has followed several of opend's innovations: we shipped interpolated expressions on day one of the fork (that was the straw that broke the camel's back) and then, after 7 years of procrastination, upstream also merged it a week later. We shipped extern(Objective-C) support, upstream backported it (and actually fixed enough bugs that I replaced my original impl with their's) a few months later. Upstream has talked about "safe by default" for over nine years. We shipped "safer by default" as a compromise (full safe by default is too much of a breaking change) a few months after forking, then a few months after we shipped it, upstream announced their own "safer by default" switch (which you have to opt into, so they kinda missed the point of "by default" but still, they followed the overall concept). For basically ever, Walter has said null checks in the language were a hard no, we implemented them and then.... guess what, a few months later, my implementation was backported (and again, a few bugs fixed so i appreciate the collaboration when we can get it) and walter decided to allow the merge. Opend shipped druntime on webassembly, looks like something similar coming to upstream. We merged the tuple destructuring PR (that was open for years again so the author was happy to get it to land somewhere!) and upstream followed there too.
There's a lot of smaller things that haven't been pulled though, like i merged a bug fix to module naming, which was an upstream PR from like 2018, a fix on library file name generation, a regression from 2019 but has a trivial workaround, a fix to redefined reflection names which everyone finds annoying, the implementation was written in 2017, but they had endless debates about syntax and i just made an executive decision and moved on but they still bikeshed... stuff like that, they're all little things but minor annoyances every time you hit them and the fixes were easy, so just do it!
Then the two bigger things I did they have talked about but probably won't do is i made the class monitor opt-in, this is a relatively big breaking change, I had to do fixes on 8 different projects. Each one took a few minutes, so not a huge deal, but still. They talked about this in an upstream meeting but decided against taking it (for now at least).
And then I changed the default init of all built in types to zero, including char and float, and this is controversial since float init to nan has legitimate advantages, and the breakage can be subtle if you don't catch it. I was on the fence personally, it more like a 51-49 vote rather than an obvious bug fix, but it is easier to explain to newbies that int and float both init to 0. In theory, you are supposed to explicitly initialize all these all the time, but in practice we know it is different.
So I think the competitive edge is pushing them a little. And I'm not anti-collaboration; I write blogs about my implementations with the hope that they'll give a little code review and that's been semi-successful, like the upstream backporters have indeed fixed bugs in my implementations so I'm happy to share back and forth, we both win that way.
jpfromlondon 1 hours ago [-]
I had no idea Code Node was still going strong, I used to goto a lot of events there
gregdaniels421 16 hours ago [-]
First day seems very LLM heavy, and sounds quite odd for Phobos 3. I would like to see Phobos 3 be more betterC forward, since I have found D to be nicer than C for WASM, but you can't use most nice things. Having a default RAII vector class for betterC and a hashmap would be super nice too.
Edit: Also would be nice to adopt move and copy semantics even closer to C++ and maybe need less explicit moves, and ideally less mess with calling __xdtor when trying to do RAII
destructionator 15 hours ago [-]
we shipped druntime on emscripten on the opend side almost two years ago, supporting everything but threads and exceptions (i tested on emcc 3.1.69, i heard a later version of emscripten broke, im not sure). see my blog post from release time: https://dpldocs.info/this-week-in-arsd/Blog.Posted_2024_10_2...
there's a contributor working with both upstream and opend adding wasi support as well, and he also got exception support working, we'll probably ship that next month.
so the full d story on wasm is progressing too.
gregdaniels421 15 hours ago [-]
What exactly is the openD Canon D split about, and as a regular person, which one should I use? Any other details you could give, or background? I haven't followed any of that and have no clue.
destructionator 14 hours ago [-]
I have no confidence left in the leadership of old D. This is an example: porting druntime to emscripten wasn't actually that hard to do, I did it in about a week of spare time in between kid and day job. Their solution, in so much as they pay attention to it at all, is to just point at betterC which remains half-assed for about a decade now (search my blog archives, here's one with them talking about "A betterC standard library" from December 2016 - https://arsdnet.net/this-week-in-d/2016-dec-18.html - and none of that has materialized ).
You might say if it is so easy, why not do it upstream? It takes years of political arguments and random ghosting to get anything done up there, all while constant (regression inducing) code churn breaks your PRs every other month, so you spend 3x the time rebasing than you ever spent writing the implementation before it is merged...... if it ever gets merged at all. I have several successful contributions to upstream D, it happens, but most the work done there is ignored. You might get some encouraging forum replies, but when it comes time to ship it? Crickets. Several former D contributors jumped ship for Zig many years ago, and it was a real loss for us (and real gain for them).
With the opend, I know if it works and delivers real world value, I can ship a release, dmd and ldc together, so minimal duplicated waste work.
What should you use? idk, opend is basically my pet project, provided in the hope that it will be useful, but THIS SOFTWARE IS PROVIDED `'AS IS″ AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE so your mileage may vary. Still, I maintain about a half million lines of code, some of which is quite old, so keeping some stability is important to me while moving forward with select common-sense, incremental improvements. Most D code works fine either way though, I've done web programming a long time, in the old school tradition, so words like "progressive enhancement" and "graceful degradation" are meaningful to me, even when being a compiler maintainer.
gregdaniels421 14 hours ago [-]
> point at betterC which remains half-assed for about a decade now (search my blog archives, here's one with them talking about "A betterC standard library" from December 2016 - https://arsdnet.net/this-week-in-d/2016-dec-18.html - and none of that has materialized ).
Oof, yeah that is definitely a pain point. Not to get too personal, but why would you continue to invest so much time in the language if upstream isn't accommodating?
Has WalterBright had any comments on this? He usually is so vocal, any hope of a remerge of the OpenD changes in to CanonD?
Anyway, I appreciate you trying to advance Dlang, I fight for it all the time at work, and usually get to do stuff in it(I am old and have privileges).
destructionator 55 minutes ago [-]
> Not to get too personal, but why would you continue to invest so much time in the language if upstream isn't accommodating?
Sunk cost fallacy lol. I got on the D train back in 2006 and of those half million lines of code I'm responsible for maintaining, about a quarter million are my own. A lot of work to make that... I have my own, from scratch: gui toolkit, terminal emulator, games, spreadsheet, web apps, shell, scriptable calculator, and more. Mostly mine but using libraries or ported third party code sometimes: music players, web browsers (one is from scratch but not terribly functional, one using chromimum libraries I'm typing this comment on right now), window manager, taskbar, the list goes on.
My whole daily work environment is made out of D code. And yeah, sure, there's alternatives, but I like mine. And a lot of it is making the apis cute. For example, I wanted to add a menu option to reset something in one of my programs last week. So I opened the code and wrote
It recompiled in about a second and a half and just like that, I can press ctrl+r to reload the defaults, or click Query -> Load Default in the menu (or alt+q and keyboard to it etc). My gui library takes care of a lot of things so I just write some functionality as-needed and use it a few seconds later.
Can I do that with Microsoft Excel? excel is a useful program too, but it takes longer to just load than it takes me to change the code, recompile, and relaunch my spreadsheet program lol.
Could I port all this stuff to other languages? Maybe. But it is less work to just maintain a stable fork of the compiler lol. (at the risk of getting flagged for being a troll again, I feel the same way about wayland... easier to maintain xorg, a program i haven't even restarted for years, than to rewrite the whole ecosystem.)
And that's the key point too, I do generally think the D language is mostly good enough as-is, so if I never committed another line of code to it, I'd still find it good enough. But it is nice if I do hit a language/compiler problem I can just fix it too.
p0nce 4 hours ago [-]
Even if you don't use D, I highly recommend watching some of the talks since I find them interesting and dense in information.
nubinetwork 2 hours ago [-]
We really have a problem naming things... this is the d language conference, not the gnome dbus configuration system...
cachius 5 hours ago [-]
Cool that the low-level configuration system and settings management tool of GNOME 3 gets its own conference!
I don't know why but dlang continues to draw me - I've really enjoyed many of the talks in the past
vips7L 14 hours ago [-]
I always try it every few years, but I can never figure out how to get a good ide experience. I’ve tried both VSCode and IntelliJ. I most recently tried to make it work for advent of code last year. Maybe I’m just too used to how good the IDE experience for Java is?
skocznymroczny 9 hours ago [-]
I think that's what it is. D IDE support is bad compared to C#/Java, but it's not that bad compared to C++. I think it's just templates don't play well with proper IDE support because it's hard to reason about the code when half of the code doesn't exist until compile time.
swyx 15 hours ago [-]
for those (like me) completely new but interested in new programming languages - can you or similar minds summarize the current appeal?
ccapitalK 4 hours ago [-]
As someone who has been using D since about late 2024, I enjoy the following things about it:
- It has a type system that catches most category errors, without having to think too much about types
- It is quite easy to read and write, and code in it has a high signal to noise ratio
- It provides a GC, but also allows you to write idiomatic code that doesn't allocate a lot (missing from a lot of gc languages, it feels like most GC languages force you to allocate more for every abstraction you write)
- It supports GC style code for things that don't need to be efficient (>98% of the code I actually write)
- I can easily micro-optimize the inner-loop code that does need to be efficient, without having to switch languages or setup ffi. I can also be relatively certain that the GC isn't firing too often in those loops, since the gc only collects when you gc-allocate
- I can use all of the native libraries with C bindings on my system, with practically zero costs for bindings
- Metaprogramming in it is top notch, I feel like every time I needed to do some type level shenanigans, I could do so in a way that actually looked like code in the end, without needing to maintain a code-generator. The way the metaprogramming works also stays fairly readable, it's not like macro_rules! or #defines or templates.
Overall, it has superseded C for pretty much everything I previously used C for, and is a joy to use for a lot of other usecases as well, I've found myself reaching for it for programs that I would otherwise write in python recently. Only major weakness in my daily experience is that you can't compile it to WASM, so I'm still using rust for that. I've considered learning Zig or Odin, but I feel like I would miss the GC for simple tasks, and D is good enough on most axes that I stopped looking for a new one true programming language to write all my code in.
zem 15 hours ago [-]
it's an evolutionary (as opposed to revolutionary) language; it is in many ways a reimagining of c++ based on decades of observing the latter's flaws and weaknesses in the real world. if you're in the c or c++ ecosystem already you will likely find D a pleasant set of improvements to c++.
WalterBright 14 hours ago [-]
For example, C and C++ still cannot compile this:
int foo() { return bar(); }
int bar() { return 3; }
pjmlp 4 hours ago [-]
Because of stuff like ADL, the declaration order matters, thus I don't expect anyone ever submitting a paper to fix that.
And even if that isn't a problem, given how ISO works, someone still needs to get that paper in and voted.
zerr 8 hours ago [-]
Funny that C89/C90 would compile this specific example just fine due to implicit function declaration feature, which was deprecated in C99.
vips7L 14 hours ago [-]
Is it because bar is defined after foo?
WalterBright 14 hours ago [-]
Yes.
It has deleterious consequences. One solution is to add a forward declaration, which is the kind of busywork a language is supposed to eliminate.
Another is to reverse the natural order of functions, with the implementation functions at the top and the interface of the module at the bottom.
After all, do you read a website from top to bottom or bottom to top?
CapsAdmin 11 hours ago [-]
Lua has the same problem with local functions, and Lua was the first language I learned that I still use today. So it feels very natural for me to see local functions with no dependencies at the top, and the ones with the most dependencies at the bottom. (but you can work around this in lua with globals, forward declarations, functions in tables, etc)
So I guess I kind of prefer seeing helper functions at the top and the main logic at the bottom most of the time.
WalterBright 9 hours ago [-]
BTW, that code snippet will compile properly with D's ImportC compiler. Proof that it is not impractical.
Edit: I think it was called "Herbception"s after Herb Sutter, and it really sounded like a good idea to me
I used to be a big fan of C++ exceptions, but eventually soured on it for various reasons. Here's an article partially addressing it from a while back:
https://dlang.org/articles/exception-safe.html
I would classify D's scope exit/failure/success as RAII actually, even if D uses a GC.
Sometimes you might not need exceptions and something like std::expected or optional is better.
In my case I use expected for some network APIs since I expect failures to happen out of my control aspart of the flow of my program, but I do not see why I would not use exceptions in many other situations, such as for non-ignorsble errors. I could think of a lack of disk space or some other fatal error thst is not under the control of the program.
If you forget to handle this, the error will cascade.
Also, exceptions do not make the signature of a function change (at least not in C++, Java checked exceptions is different). This means that the plasticity for adding errors at any depth of the call stack augments without bypassing any error silently.
All in all, I would say exceptions should be the main mechanism in normal circumstances and for expected errors you csn use error/result types.
I personally much prefer Rust style Result which also can't be ignored, and puts fallibili5y in the function signature.
In Java exceptions can be part of a method's declared type information, so handling is checked at compile time and IDEs can display the info.
Unfortunately certain Java missteps made this design unpopular these days. For example, for many years new String(bytes, "UTF-8"); made it mandatory to catch a UnsupportedEncodingException despite the language spec guaranteeing UTF-8 would be available. A later version of Java addressed it, but still...
For Rust result in C++ you have optional and expected. But they have their own problems, like rewriting function signatures all the way up the stack if you notice an error was possible when adding code.
Your code shouldn't need to make assumption about whether exception are being thrown or not.
Your mistake is thinking that a function potentially throwing means you need to catch it.
D's scope exit/failure/success is built on top of RAII and has nothing to do with the GC.
> I would say exceptions should be the main mechanism in normal circumstances and for expected errors you csn use error/result types.
Come to DConf (or watch the live stream) and I hope I can change your mind, or at least challenge your conclusions!
What I meant here (I do not know the mechanism) is that I am aware that D has a GC. This means, correct me if I am wrong, that D does not use destructors (like C++) for scope exit/failure/success, though they are scoped mechanisms (RAII-like).
> Come to DConf (or watch the live stream)
I always follow D (even if I did not use it intensively). I have extremely high respect for you as a language designer and as a technician. Your knowledge is very refined, so I never take your opinions lightly.
Probably one of the most knowledgeable persons in the industry for native language design. However, I am far and cannot attend, so I will definitely watch it.
> or at least challenge your conclusions!
No problem in challenging them. I am always open to do things better. This is just my practical experience as I implement stuff so far.
I currently think exceptions seems like a good default mechanism (apparently at least) compared to alternatives. But I also think other mechanisms have their place and can/should be used even in the same program, just for different things.
All mechanisms have trade-offs. I just talked about defaults from my POV for the kind of software I develop (mostly server-side, some client-side, and not embedded in the extremely constrained sense).
-----------------------------
One question: I tried to use D several times in my career (20 years of C++ experience here, roughly). I found it a lot of fun. I like it better than more "modern languages". I like the plasticity D provides. But I am not sure how it would work if I want to do:
I do like D a lot, but the problems I had before were more related to tooling (autocomplete, I use mainly Emacs but did not try for a few years) and toolchain maturity.It would be ready for all of the above? Also, very very handy would be to wrap C++ code and C code. I saw that D had an ongoing effort for C++ compatibility better than other languages, but I am afraid it could be half-broken. Even if it is, it is documented what works and what does not work? That would help a lot.
Thanks.
It does, but the user doesn't see them.
There are people working on 1, 2 and 3.
> 4. backwards compatibility (heard complaints of versions breaking stuff frequently around).
We listened, and cut way back on breaking changes. Now we have editions.
> 5. interaction with C++.
C++ has gotten to the point where it would take another decade of my time to wire in ImportC++. However, if you stick with C++'s C interface when interfacing with D, you should be fine. D will also work with C++ name mangling, but all the complexity of C++ templates and such is just too much.
And thank you for the kind words! I definitely appreciate it.
> I am far and cannot attend, so I will definitely watch it.
Wonderful!
There is a fork of D compiler called OpenD which has some WebAssembly support with garbage collection and standard library. I've used it, it works for the most part, but there's bugs and if you encounter any issues then you're on your own.
It has better than that, but it is a bit clunky compared with C++(just use struct instead of class). You can have proper destructors, but if you have a container you need to be more careful than in C++.
In D exceptions are the default like in C++ and you have to opt out with nothrow or extern(C) or betterC.
Really try some D code in a bigger situation it is 90% good and almost worth using over C++, but if you can't have GC it is a huge pain, but better than C.
Also, recently the GC implementation received a big modernization upgrade.
Additionally, Khalil Estell has made an excellent work proving that the way exceptions are currently implemented is not optimal and there is plenty of room for improvement, when someone cares about their implementation.
"Cutting C++ Exception Time by +90%? - Khalil Estell - CppCon 2025"
https://www.youtube.com/watch?v=wNPfs8aQ4oo
I can never get past the ugly syntax.
Standard exception handling is:
- Whenever an error happens, the program puts a description of it into an “exception” object. You go from the innermost dynamic scope to the outermost looking for handlers. Once you find a handler willing to accept that type of exception, you unwind to the point where it was installed then invoke it, passing the exception object.
Condition handling[3] is:
- Whenever an error happens, the program puts a description of it into a “condition” object. You go from the innermost dynamic scope to the outermost looking for handlers. Once you find a condition handler willing to accept that type of condition, you invoke it as a regular callback, without unwinding, passing the condition object.
- The handler then packs up some data into a “restart” object. You go through all the dynamic scopes again (remember that the erroring function is still active). Once you find a restart handling willing to accept this type of restart, you unwind to the point where it was installed then invoke it, passing the restart object.
(I am omitting things outside the happy path: a way for the exception/condition handler to punt, what happens if the condition handler does not invoke a restart, etc.)
As far as the benefits of this two-phase approach, Practical Common Lisp gives an example[4] of a single-record parser that raises an “invalid record” condition, a loop around it that installs a “skip to next record” restart, and finally the caller can make the policy decision on what to do for invalid records.
As another example, Common Lisp signals an “unbound-variable”[5] condition leaving the “use-value” and “store-value” restarts in scope, then the REPL installs a handler that offers them interactively. (My own half-serious example of a DOS abort/retry/fail prompt is in this vein too, chosen mostly because it feels strange that you can’t do it in a conventional exception system.)
[1] https://package.opendylan.org/dylan-programming-book/excepti...
[2] https://news.ycombinator.com/item?id=31196046
[3] https://www.nhplace.com/kent/Papers/Condition-Handling-2001....
[4] https://gigamonkeys.com/book/beyond-exception-handling-condi...
[5] https://www.lispworks.com/documentation/HyperSpec/Body/e_unb...
By the way, big fan of D even though I don't get to use it much. Appreciate your work!
[0]: https://opendlang.org/
There's a lot of smaller things that haven't been pulled though, like i merged a bug fix to module naming, which was an upstream PR from like 2018, a fix on library file name generation, a regression from 2019 but has a trivial workaround, a fix to redefined reflection names which everyone finds annoying, the implementation was written in 2017, but they had endless debates about syntax and i just made an executive decision and moved on but they still bikeshed... stuff like that, they're all little things but minor annoyances every time you hit them and the fixes were easy, so just do it!
Then the two bigger things I did they have talked about but probably won't do is i made the class monitor opt-in, this is a relatively big breaking change, I had to do fixes on 8 different projects. Each one took a few minutes, so not a huge deal, but still. They talked about this in an upstream meeting but decided against taking it (for now at least).
And then I changed the default init of all built in types to zero, including char and float, and this is controversial since float init to nan has legitimate advantages, and the breakage can be subtle if you don't catch it. I was on the fence personally, it more like a 51-49 vote rather than an obvious bug fix, but it is easier to explain to newbies that int and float both init to 0. In theory, you are supposed to explicitly initialize all these all the time, but in practice we know it is different.
So I think the competitive edge is pushing them a little. And I'm not anti-collaboration; I write blogs about my implementations with the hope that they'll give a little code review and that's been semi-successful, like the upstream backporters have indeed fixed bugs in my implementations so I'm happy to share back and forth, we both win that way.
Edit: Also would be nice to adopt move and copy semantics even closer to C++ and maybe need less explicit moves, and ideally less mess with calling __xdtor when trying to do RAII
there's a contributor working with both upstream and opend adding wasi support as well, and he also got exception support working, we'll probably ship that next month.
so the full d story on wasm is progressing too.
You might say if it is so easy, why not do it upstream? It takes years of political arguments and random ghosting to get anything done up there, all while constant (regression inducing) code churn breaks your PRs every other month, so you spend 3x the time rebasing than you ever spent writing the implementation before it is merged...... if it ever gets merged at all. I have several successful contributions to upstream D, it happens, but most the work done there is ignored. You might get some encouraging forum replies, but when it comes time to ship it? Crickets. Several former D contributors jumped ship for Zig many years ago, and it was a real loss for us (and real gain for them).
With the opend, I know if it works and delivers real world value, I can ship a release, dmd and ldc together, so minimal duplicated waste work.
What should you use? idk, opend is basically my pet project, provided in the hope that it will be useful, but THIS SOFTWARE IS PROVIDED `'AS IS″ AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE so your mileage may vary. Still, I maintain about a half million lines of code, some of which is quite old, so keeping some stability is important to me while moving forward with select common-sense, incremental improvements. Most D code works fine either way though, I've done web programming a long time, in the old school tradition, so words like "progressive enhancement" and "graceful degradation" are meaningful to me, even when being a compiler maintainer.
Oof, yeah that is definitely a pain point. Not to get too personal, but why would you continue to invest so much time in the language if upstream isn't accommodating?
Has WalterBright had any comments on this? He usually is so vocal, any hope of a remerge of the OpenD changes in to CanonD?
Anyway, I appreciate you trying to advance Dlang, I fight for it all the time at work, and usually get to do stuff in it(I am old and have privileges).
Sunk cost fallacy lol. I got on the D train back in 2006 and of those half million lines of code I'm responsible for maintaining, about a quarter million are my own. A lot of work to make that... I have my own, from scratch: gui toolkit, terminal emulator, games, spreadsheet, web apps, shell, scriptable calculator, and more. Mostly mine but using libraries or ported third party code sometimes: music players, web browsers (one is from scratch but not terribly functional, one using chromimum libraries I'm typing this comment on right now), window manager, taskbar, the list goes on.
My whole daily work environment is made out of D code. And yeah, sure, there's alternatives, but I like mine. And a lot of it is making the apis cute. For example, I wanted to add a menu option to reset something in one of my programs last week. So I opened the code and wrote
``` @menu("&Query") @accelerator("Ctrl+R") void Load_Default() { query.content = readTextFile("default.txt"); variables.content = "{}"; } ```
It recompiled in about a second and a half and just like that, I can press ctrl+r to reload the defaults, or click Query -> Load Default in the menu (or alt+q and keyboard to it etc). My gui library takes care of a lot of things so I just write some functionality as-needed and use it a few seconds later.
Can I do that with Microsoft Excel? excel is a useful program too, but it takes longer to just load than it takes me to change the code, recompile, and relaunch my spreadsheet program lol.
Could I port all this stuff to other languages? Maybe. But it is less work to just maintain a stable fork of the compiler lol. (at the risk of getting flagged for being a troll again, I feel the same way about wayland... easier to maintain xorg, a program i haven't even restarted for years, than to rewrite the whole ecosystem.)
And that's the key point too, I do generally think the D language is mostly good enough as-is, so if I never committed another line of code to it, I'd still find it good enough. But it is nice if I do hit a language/compiler problem I can just fix it too.
https://en.wikipedia.org/wiki/Dconf
And even if that isn't a problem, given how ISO works, someone still needs to get that paper in and voted.
It has deleterious consequences. One solution is to add a forward declaration, which is the kind of busywork a language is supposed to eliminate.
Another is to reverse the natural order of functions, with the implementation functions at the top and the interface of the module at the bottom.
After all, do you read a website from top to bottom or bottom to top?
So I guess I kind of prefer seeing helper functions at the top and the main logic at the bottom most of the time.