Let's learn D game programming development (2021) [video]
youtube.com
youtube.com
I just wish it had more popular traction - it's much better to program in than Rust, Go or even C# as a language, but the community support is lacking.
I look up how to do X, find very few resources, more than half mention D1. Compare that with looking up X in Rust or Python, how many mention Python 2 or Rust before the editions.
You can start your D usage with these examples: https://github.com/p0nce/DIID
I don't know the status of https://code.dlang.org/packages/libtcod-d
"Rust seems obstuse" doesn't mean anything. On the other hand, I personally think that Rust is not the most productive language, overall, for game development (I'm familiar with Rust gamedev). This consideration includes the hard truth that as of now, the game libraries are young and buggy.
In an theoretical world, where all the languages have stable and equally functional game libraries/engines, in my opinion, the most productive language is something with deterministic (manual) memory management, but less memory safety (=overhead) than Rust, but that is still safer than C-family languages. I can picture D fitting this characteristics, but also other modern languages. This does not apply to areas where where safety is paramount (e.g. networking).
When I say that Rust seems obtuse, I mean I've been bashing my head against its philosophy and syntax for some time without reaching the magic "hey this works and I'm suddenly productive" summit (or at least plateau).
I've come to the conclusion that it's not for me, but my interest in it stemmed from frustrations with Python and my memories of enjoying writing 'C' in the 90s. I find C++ a language without an underlying philosophy and seems like a horrid patchwork of things; Java is frustrating and verbose. C# is very Windows centric, which I'm not adverse to exactly, but I don't run it. Various other languages I've thought about and discarded.
I was toying with Go as that seems to have many fans, and seems to have wheels, but I'm cautious given some of the criticisms it comes under. D was not on my RADAR, but now I'm quite interested and probing its good and bad points. It looks promising on a casual look.
You're right, of course, "lots of developers who spend time inquiring and researching about game writing platforms (languages, libraries, engines) but end up writing nothing. "
Most people come from the point of view of they enjoy playing games, so they think they would enjoy writing them. Same with reading novels/writing them, and probably many other spheres of human creative endeavor.
I'm not saying I'm immune from this kind of thing, but my ideas are very modest, and if I fail to implement my game, no harm will come from it; the opposite in fact, as the very act of solving programming problems is as productive as solving a crossword puzzle, and will serve, if nothing else, to keep my mind sharp (as my current job requires no programming ability whatsoever).
I don't enjoy playing games, I'm tremendously bad at them and so don't get much positive re-inforcement on them as an enjoyable activity. But programming is fun, and that's what I'm looking for.
Will definitely revisit when things settle.
Beyond that D is a good language for writing software in. all language communities have fractures unless the language attracts lots of either new or bad programmers who haven't formed opinions yet
If you're talking about the whole Tango/Phobos (2 std libs) thing, it's fixed and Phobos won. But now there are optional function attributes such as @nogc (checks that the code doesn't trigger the GC), @safe (memory safety checks) and nothrow that's causing a bit of a problem.
For example, not all libraries are @nogc. So if you want to use some library in your @nogc code and the library is not marked as @nogc, you can't use that library. This is not as bad as the two standard libraries problem but it restricts the libraries you can use.
The attributes are optional like I said, you can just ignore them and write code that uses the GC (not @nogc), code that is not explicitly checked by compiler for memory safety (not @safe) and code that throws exceptions (not nothrow).
Of course this is sort of expected in multi-paradigm languages, like some people disable C++ exceptions. But in D's case it feels like the compiler and library developers' efforts are spread thin.
Write the code first then measure it.
Sort of undecided on the exceptions though. The Result / Option type in Rust is pretty nice to use (and !?*T in Zig, which is nicer if you ask me). It forces you to handle exceptions explicitly which is pretty nice and you can be sure there is no overhead introduced by the compiler for handling exception stuff.
I'd probably wrap all the exception throwing functions in my D codebases with Result type if we had language level support for sum types and match syntax. I know we have it in the standard library, I want it in the language with nicer syntax.
I also want the GC to be replaced with deterministic destruction using RC + ownership analysis and optimizations like Lobster does, but that's wishful thinking territory.
D doesn't return values when an exception is thrown as far as I know. How are exceptions' costs are paid by tricky implementation?
I thought exceptions require allocation and run-time type info and therefore always introduce some cost (this goes for D and C++). I guess returning values and allocating error strings statically can help with that (or maybe allocate some exception buffer on program start -- but that's technically "overhead"). Am I wrong, or missing some important context related to exceptions?
Lots of people do statically allocate their errors now.
Implementing stack unwinding properly is not trivial.
That said though, yeah, I don't think any of them use `@nogc`. I've actually tried to get the gc to interrupt audio code before and couldn't even hear it. I'm sure a bigger heap to scan might cause a problem in some situations, but these fears are really overblown in the popular commentariat.
Anyways, the strong concurrency story in Go finally bought me over there though.
I still miss the super readable (almost python-like) syntax from D though.
Running functions alone is not that interesting, and neither really is generating code. You can do those (arguably better for some cases) with helper programs as a separate build step. But reflection is non-trivial to do externally, so that's the biggest value add, and using it with all three pieces let you close the loop.
But what I’ve mentioned is also very related to the ergonomics of compile-time metaprogramming, since these techniques are all useless if it severely increases builds times up to the point that developers have to use it sparingly. Only Nim and Jai has fully gone the route of using a bytecode VM for compile-time evaluation, while D had a similar project back in 2017 that was abandoned, and for other languages (C++, Zig, etc.) it’s still in the planning stage.
Unlike some D programmers I don't mind rust but compared to C and C++ the primary difference I'd say is that D has a lot of features that you'd have to emulate with either macros or recursive templates that means that the source files end up much cleaner.
If you want to declare a struct with N members where N is declared at compile time, in C++ it's usually a question of doing a bunch of compile time magic that leaves a roadside picnic of SFINAE everywhere whereas in D it's just a "static foreach" loop inside a template.
Like other people above, I really liked the language, and I wish could use it at work. For me it hit a good spot midway between C# and C++. The documentation was complete enough for me. Although IMO AOC isn't representative of "real world" programming.
Regarding the GC, I had no major problems with it, but when faced with frequent allocations it performed slightly worse than what I'm used to from C#, in terms of memory consumption. In C# code, in places where I'm not concerned with performance, I'm used to allocate many small and temporary dictionaries freely without a hitch, the dotnet GC does a great job of releasing them as I go along.
In D however I wrote code using the same style (allocating relatively small temporary dictionaries in a loop) and saw memory usage ballooning very quickly, to several GBs.
At the end the intended solution for the AOC problem shouldn't have involved this many allocations anyway, so I didn't spend time investigating this too deeply.
Small dynamic arrays did not cause this problem, though, as far as I remember, the GC seemed to collect them well enough.
Thanks to reflection features I can serialize/deserialize entire scenes just by annotating the fields in structures as needed, and can also autogenerate editor fields for inspector views. With C++ I'd have to do some out of place looking define magic to generate my structures and it wouldn't just work with any struct.
Unlike my fellow D game developers I don't fight the GC. I don't use any of the @nogc features in D or obsess about manual memory management. I have a fairly beefy machine, but still, I think the dangers of D's GC are somewhat overblown. There was a blog article back in the day by someone writing a 3D space game in D and it was often referred to as an example of how bad D's GC is, but there wasn't really enough data in that post to know about the methodology. Firstly, in a game most of the data should be preallocated anyway, in the game loop there isn't that much to allocate. Secondly, D has value types, so there's much less pressure on GC because you can stack allocate things like vectors or matrices. Sure, in other GC languages a sufficiently smart VM could probably optimize that out and avoid the GC, but I doubt it would catch most cases.
I also like how easy it is to interact with C. This grants me access to gamedev libraries such as bgfx, wgpu-native, ODE, NewtonPhysics and many, many more. C++ interaction however never cared much for. I feel like D spent too much effort here, even adding language features (copy constructors) to interact better with C++. In the meantime, it seems that it's still hard to interact with C++ libraries from D, and ironically I feel like languages like Rust or Zig have a better interop story with popular C++ libraries like Qt or Bullet, despite not investing as heavily into that.
My main current issue with D is that as a community project, it seems to lack some direction. There's some very talented people working around the project, but most of that work is done on a specific issues and projects people want to work on. Since a lot of the work on D is unpaid work, you can't force people to do what you want them to do. However, the language lead team should influence the direction of the language and provide a path forward. It's getting better in recent times, so there is a lot to look for in that aspect.
The multiparadigm aspect of D and its flexibility can be detrimental too sometimes. There are some subgroups in the language community that approach the language in a specific way and feel their way is the true "D way". For example, you have OOP folks that would like more features like named constructors, you have template metaprogramming folks who would like to remove most D features such as classes and just replace them with some metaprogramming template magic, you have folks that disable the GC and avoid the standard library from the get-go. This causes some friction, because any new feature for the language would have some opposition from the other side who will consider it bloat and unnecessary. In some ways the article about "Lisp curse" applies well to D.
These factors however don't really influence me personally, because I get to pick the features I want to use and can avoid the ones that I don't see the benefit of.
As for style, we have very few issues getting non-D programmers writing D. They don't know the fancy stuff exists until we tell them when they need it.
These distractions have allowed competition to come up, and C++, Java and C# to strengthen their position by improving in areas of metaprogramming, modules, type inference and AOT compilation, making the transition to a smaller ecosystem less appealing, just to use such features.
I recently noticed that Andrei Alexandrescu is at NVidia now, and I imagine that most likely he will continue focused on C++ instead, or maybe NVidia is going to add D to CUDA?
I don't know, it is a pity, because the community is great.
Don't make me work to build something by forcing me to research every piece of it. You can do all sorts of things in Go out of the box that get you building production tier work right away.
However, the community is just too small (which has several consequences, including lack of packages, web frameworks, etc.), and for serious projects that I want to move to commercialization, I had to move to Rust.
You can catch C++ exceptions
The two main reasons i chose Free Pascal are (both of which are important):
1. There is a strong aversion to breaking working code in FPC which to some extent is also part of the overall ecosystem. Code i wrote 20 years ago still compiles because any new features are made so that they don't break existing code. Exceptions exist, like when how string are handled changed, but that was a quick fix (in all of my programs i only had to apply a single line fix twice).
I don't know D's story on that but i've heard that there were updates to the D compiler that broke code (but i don't know how severe that is - FPC also introduced theoretically breaking code almost every version but in practice it is usually extreme edge cases, compiler bugs or very internal things and these latter only change like per decade or so).
In general i want code that i know it worked today to keep working in 10 years from today so i can focus on other things instead of babysitting it (i do copy/paste code i know that works from my existing projects all the time - even the engine i linked above contains a lot of code from older projects, the earliest bits being from 2007 or 2008).
This is even more important if i decide to switch to a new language because i wouldn't be able to use much of my existing code so any new code i write i want it to be valid for years ahead.
2. Lazarus and LCL. Think open source Delphi or Visual Basic with a real framework and a strong language. Lazarus is a "real" IDE in that it isn't just a glorified text editor attached to a compiler but it knows the language and builds a database of the entire project in memory, which allows for it to manipulate the code for you (this avoids a lot of boilerplate that come out of the verbose syntax Free Pascal has). More importantly it provides a WYSIWYG visual editor for GUIs (very important for tools) and a rich application framework (LCL) that is designed around Lazarus - these aren't independent bits someone stuck together with some glue, they are all made with each other in mind, which provides a more coherent experience than if someone stitched things together (if anything most of the issues Lazarus/LCL has is from things outside of their control, like the backend GUI toolkits). I have used a lot of other GUI approaches, Lazarus beats them all hands down. And as a cherry on top Lazarus is a native app written in Free Pascal itself and is very responsive - it even runs on older Rasberry Pis with relatively low resource requirements.
Sadly D doesn't seem to have a decent GUI story, let alone something like Lazarus and LCL. A promising library was dlangui[1], but that is a 3rd party library that looks like the author decided to abandon[2]. Honestly IMO without something that is adopted by the core D developers (and by extension the rest of the D community) i can't see anything flourishing there - it'll instead be a bunch of independent solo devs making their own half-baked stuff for eternity (btw, yes, Lazarus/LCL are technically a separate project but in practice there is strong overlap between the two projects' developers and they share resources). At best you get bindings to Gtk+ but that has its own share of issues and bindings to other toolkits (e.g. wxWidgets) look abandoned.
I occasionally check out D to see what is the status wrt the above but for years things do not seem to change. I do hope that at some point D will have a good GUI application framework and a good native IDE that understands the language itself.
[0] https://i.imgur.com/1Y5hL26.png
Am I the only person who doesn't view this as a good thing? If you want to compile code your wrote 20 years ago, use a compiler version from 20 years ago. Forcing backwards compatability hinders a languages growth and forces it to stick by decisions that, in hindsight, may not have been the best.
I think it's great that there are languages like FreePascal, C, and Common Lisp, which make an effort to think in terms of decades. The existence of these languages frees everyone else up to break compatibility when they want to, because projects which need strong stability guarantees can chose these languages for that project.
I want to compile code i wrote 20 years ago alongside code i wrote 10 years ago and yesterday, not just compile some old project. Though even compiling some old project should be as friction free as possible too.
The point is that once i write some code that i know works, it should keep working in future versions so i wont have to worry about updates (which is now the case with both Free Pascal and Lazarus/LCL - i even use the development versions directly from the repository).
> Forcing backwards compatability hinders a languages growth and forces it to stick by decisions that, in hindsight, may not have been the best.
And ignoring backwards compatibility forces all users of the language (which unless it is a toy project, are way more numerous than the developers of the language) to waste time keeping their projects up to date instead of working on new features and/or bugfixes for their projects.
Also Free Pascal does have a way to avoid this (to some extent) using modes and modeswitches - the former affect the Pascal dialect being used for a file (which can be mixed with other files with other modes) and the latter enable/alter syntactical features that would otherwise break existing code, thus allowing it to be improved piecemeal without breaking anything else.
AFAIK similar features exist for some other languages (i remember reading that Rust's epochs are meant to do something like that though i don't know if files from multiple epochs can be mixed).
[2]Extending Pegged to Parse Another Programming Language:
[3]Transcompilation into D:
Pascal is not a bad language for engineering, in some aspects it is even better than D. Still, the combined features of D made it a winner over all, in our case.
[1] https://dlang.org/blog/2018/06/20/how-an-engineering-company...