| A Postmortem of Game Programming with Digital Mars’ D Programming Language | |
|
A Postmortem of Game Programming with Digital Mars’ D Programming Language
PrologueOne thing I find very interesting is different computer languages, their development and their differences. I spend most of my time in C++, but the little exposure I’ve had to LISP or to other languages always leaves me wishing that C’s macros were cleaner, or that C++ had a way to implement a nice multi-variable for-each. This past month I’ve been on vacation and since my wife would be bringing her laptop, since I didn’t feel like bringing the MSVC++ CDs or backing up my projects directory, and since I didn’t really have any current project I wanted to work on, I decided to break out Digital Mars’ D Programming Language and try to learn it. I had read through some of the first pages of Digital Mars’ D’s documentation and propaganda, but I had never taken the time to actually work with the language. After a few weeks of fiddling with it when not at the pool, I have to say I really like the language. Two major design philosophies that I feel when working in D are: 1) Things that you do a lot should be simple and 2) A language should be clean, simple and consistent. This diary is about the specific joys and difficulties of working with D. D is billed as a ground up rewrite of C – a new version of a good language, or everything that C++ wishes it could be but never will be. Complaint #0: “D” is horrible to search for. “C++” is a distinct string. I ended up having to use “D Programming language” or “Digital Mars D” every time I wanted results. Searching from within DigitalMars.com and then forcing Google to use the within domain and the “-archive” flag helped when I wanted language specific answers. InstallingGoogle is everyone’s best friend. “D Programming Language Download” drops you to a page with all the downloads. I was running Windows XP Pro in the hotel room, so I grabbed It’s a quick download, which is nice because I’m on dialup at home. I initially wanted to run the programs from the desktop, so that I could easily clean everything off when I left the hotel. That didn’t work out in the brief time I spent fighting, but the following files seem to be important if you want to bash D into running from a non-root location: I still didn’t want several folders littering my C: root, so I extracted the I created a projects folder under I like using Textpad as my editor with a modified The batch file was configured to run in My first A good test of whether your install worked is to run your command window, then navigate to The online documentation, a lot of which is installed with the compiler, is very readable. I’m a bit odd, but I found the documentation to be enjoyable reading. (I find Microsoft help to be useless and Microsoft online documentation to be needlessly obfuscated. (Unix’s The second lack in the documentation is its terseness. (This may be aggravated by the difficulty I found in finding answers). The documentation seems to be written by extremely smart people to explain to other extremely smart people the differences between C++ and D. (Or written to explain to a writer of another D compiler exactly how to implement it.) I would prefer that some things that should be obvious or are explained under another topic be spelled out in their own page. Something more on the lines of Programming in Lua by those guys, or The C++ Programming Language by Stroustrup. There are answers to many questions in the documentation, but you must randomly search for it. Only a little of the documentation appears to be available from the D Programming Language home page.
Remember, I said I found the documentation to be an enjoyable read. Since D has built in support for code auto-documentation, the library documentation tended to be complete. It also had a comprehensive table of contents as a sidebar. Again, repeatedly listing requirements and error cases would be nice for each function, instead of writing the doc once per module, but again this is a language written by very smart people for very smart people.
I started by grabbing the “hello world” or “word count” app, I forget which. I copied it from I’ve wanted a nice directory diff tool for a while now. I realize that there are many of these available, but I’ve always been busy when I needed one, I’m too cheap to spend the $20 for a commercial one and too lazy to search for a good open source one. Besides, not finding a good tool has left me this opportunity to write one. When I got to the hotel, I immediately copied my 1000 crappy 80’s games CD on to the computer and Windows copy barfed after 975 of them. This left me with no good way of knowing which of the 100,000 files the problem was, but I tried to manage. This is a perfect illustration of one application of my directory diff tool. I want to be able to repair large directory copies, not merely delete and retry.
The first job is to write a tool which can list all files recursively across a folder and report the findings. D has a function with this functionality; listdir. I immediately encountered the unacknowledged recursive NTFS It’s probably a good thing that the D compiler is a multi-pass thing. There are no header files and no predeclerations. However, because the compiler is multi-pass, it tends to barf on an early pass before moving on to a next pass. I think there are 3ish compile passes and 1 link pass. If your code is significantly messed up, you will bring your number of errors down past 1 several times only to see new sets of errors crop up. (It could also be that I just caused more errors by fixing one) The errors usually refer to the line that failed, but not always. Factoring out code and block-commenting code seemed to be required. I had a problem with using an anonymous enum which reported the error on the declaration line, not on the usage line.
When debugging in MSVC++, you get the line, call stack and all other information you could want about the failing code. When the program crashes, it would be nice to get a line number, a function name, or the option to debug the problem. D just dies to the command line with an error message and no context. The same problem applies to the asserts. MSVC++ asserts are continuable, possibly an implementation failure, since asserts should be fixed. It would be nice to be able to continue past asserts to get a comprehensive list of failures, but I recognize the point.
Being able to toss strings and arrays of objects around as parameters and return values without worrying about the memory leaks is really nice. In C++ you must always be aware of whose responsibility an object is. D is really nice about allowing you to pass references (low overhead on function calls) around without worrying about later releasing the objects or performing expensive copies.
After finishing my directory diff tool and deciding that the HTML source code reformatter was too boring to work on; I returned to trying to get some kind of a game working in Digital Mars’ D programming language.
I downloaded Derelict, the everything-related-to-games-or-graphics linkage library for D. It takes good advantage of D’s ability to statically and dynamically link to C without hassle. I liked Derelict. Add one additional initialization function call and the C code for your OpenGL or SDL program is very nearly ready to run.
Derelict needed Build One of the tutorials I read recommended breaking Derelict’s zip file layout by searching for every subdirectory named “derelict” and then dropping those files into DMD’s SRC directory. This worked very well.
I grabbed one of Nehe’s articles (Try 6 and 15, I forget which I used) as a base, started with the OpenGL “flying a little plane around the screen with the keyboard” and built upwards to a Asteroids / Bosconian type game.
I took that basic file and started adding layers of functionality. I mildly kept in mind how I would be using my code in the future, but mostly I just kept a list beside my keyboard of the features I wanted to add, and then refactored the code as I went.
I haven’t been a fan of C# and Java’s one file layout because it seemed cluttered to me. A header gives you a nice concise list of what functions and structures are available, leaving the source file to do actual work in. Using BUD made splitting D source files very easy, since once the files marked what imports they needed, the compile just worked. D has nice class / object oriented support, but doesn’t mandate it religiously. I find it easier to refactor stray functions out into new files than to break an existing class in half to make navigating the files easier.
If I had worked much longer with my little toy game, I would have broken the render and keyboard process functions in half. I had code for both gameplay and the main menu in the same functions and that looked ugly. I would probably add a function pointer “process mode” system to handle which render and process was currently executing. After adding many enemies and weapons, I was starting to get irritated at the duplicated code in the “behaviors” file. Most of that code could be converted to data and placed in an external script or in an .INI type definition file.
In D, strings are a built-in part of the language. But it’s better than that. In D, arrays are a first-class part of the language. Strings (being arrays of characters) benefit from all the cool things you’ve ever wanted arrays to do.
On these first two projects, I didn’t use D’s built-in Unfortunately, the simplest version assert is about the only built-in testing function. More about that next.
In C, macros are seriously powerful tools. I don’t accept the arguments of people that macros are ugly, type-unsafe, code-unfriendly, and un-debuggable. That is all perfectly true, but in C/C++, there are jobs which can be done either only by macros, or can be done best by macros. Inline templated functions help, but macros still fill a niche.
D doesn’t have a macro preprocessor. There’s static if, static assert, templates, delegates and mixins. The big point here is that there isn’t a separate macro language you have to learn. The entire D language is available to you AT COMPILE TIME! (There are also nested functions, which help alleviate the macro problem, but that’s a different topic.)
Unfortunately, D ends up being short a little functionality by removing the full preprocessor. After working with the language a little, I wanted to add a more comprehensive Built-in source documentation. I realize Java and C# and other development platforms offer this. D is nice in that this is part of the basic compiler (add one flag and you get a nice HTML file showing your documentation) and that it was designed in from the start. Further, the documentation thing isn’t some separate source file based xml parser: It’s part of the same language. (CONSISTENCY!) Add an extra trailing comment character to your comment:
autos are really, really nice. In C++, if you want to iterate across a list, you have to do some nonsense like:
autos are also nice for weird functions where you just need the return value of a function.
I had noticed earlier that D doesn’t have the -> or * operators. The language seemed to really downplay the differences between variables, references, pointers and smart pointers. I thought that it was a nice touch, since the compiler knows what each type of variable is and doesn’t need a syntactic hint. However, I got several problems trying to build my objects and later in building a vector class for my objects.
D objects are all dynamically allocated – always.
I also had trouble checking object pointers against null. I hated this one. Because the difference between pointers, references and object variables is mildly hidden, checking an object for null is different than in C.
Apparently, the right way is to use a special is operator for this.
As I build my classes, in this project particularly the vector class, I generally don’t add member functions or functionality until I’m actually using it in the client code. D’s operator overload is a bit different than C++’s because the operators are all named as functions (opMul, opAdd), instead of as operators (operator*, operator+). This adds clarity as to what the functionality being added is, instead of drawing attention to the specific syntactic sugar the language will let you use in calling. I think this naming scheme (while requiring a function name look-up to add operators) also reminds users that these functions can be used in callbacks.
Nested functions are cool. You can use them both as parameters for delegates and as static nested functions they are a nice way to handle simple topical tasks. In C++ I would have either done a huge block of logical statements or a separate static function placed earlier in the file. This moves the control logic away from where it is actually used. In D, you can define a little utility function (with or without access to all the variables of the parent function) and use it multiple times thereafter. One way to think of non-static nested functions is like class member functions, except instead of a hidden data pointer to an object of that class being passed to the function, there is a hidden data pointer to all the local variables of the parent function.
Have you ever programmed in BASIC or Pascal? Did you then move to C/C++ and wonder how those programmers ever got any work done? What is it with those programmers and their dot-target fetishes? ( “.” or ”->” ) That’s right. C/C++ is completely missing the Here’s how it works for everyone who hasn’t seen this yet. In C/C++, you are continually typing
Enter D is really cool because it is link compatible with all C libraries ever written (if they use the gcc compiler). There’s a bit of work to get the On another project, I started trying to write win32 apps using D. I found that the Phobos library std.windows was missing a lot of the win32 library. It was very simple to use the MSDN documentation to get C function prototypes for each function I needed and then add them to my project. D automatically linked to the windows libraries.
I really liked Digital Mars’ D Programming Language. There are some rough edges, but these are getting ground off as more people use the language. It felt easier to do what I want to do. I’m just learning it, but even with looking things up in the help, working in D felt good. When I wanted to write a function or move a block of code around, there was less boiler plate and fewer interruptions to getting the work done.
The Computer Language Benchmarks Game puts D very close to C/C++ in performance, while most of the irritations which would drive people to Java/C# are removed.
D is a simple clean language with all the features you’ve been dying to have. D is what C has always wanted to become and what C++ should have been from the start.
About the Author
Jonathan has been programming since 1992. He saw a friend programming Hangman in GWBASIC, became addicted to the idea of global domination through control of computers, and hasn't stopped programming games yet. He has a BS-Computer Science from the University of Missouri - Rolla. Jonathan currently works for Volition writing video games for the Xbox 360. His interests include computers, computer programming, programming languages, game programming, computer games, space elevators and nursery rhymes. He is married and has 4 children who have a guinea pig.
Discuss this article in the forums
See Also: © 1999-2008 Gamedev.net. All rights reserved. Terms of Use Privacy Policy
|