May 10, 2017 Re: "I made a game using Rust" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On Wednesday, 10 May 2017 at 15:03:19 UTC, Adam D. Ruppe wrote: > On Wednesday, 10 May 2017 at 14:02:38 UTC, Adrian Matoga wrote: >> Would you mind giving some examples? > > What bothers me on a regular basis is overloading. Basic case: > > $ dmd lll > lll.d(6): Error: none of the overloads of 'foo' are callable using argument types (int, double), candidates are: > lll.d(1): lll.foo(int a, int a) > lll.d(2): lll.foo(int a, string s) > > Contrast that to g++: > > $ g++ lll.cpp > lll.cpp: In function ‘int main()’: > lll.cpp:7:14: error: no matching function for call to ‘foo(int, Foo)’ > foo(0, Foo()); > ^ > lll.cpp:7:14: note: candidates are: > lll.cpp:1:6: note: void foo(int, char*) > void foo(int a, char* b); > ^ > lll.cpp:1:6: note: no known conversion for argument 2 from ‘Foo’ to ‘char*’ > lll.cpp:2:6: note: void foo(int, float) > void foo(int a, float b); > ^ > lll.cpp:2:6: note: no known conversion for argument 2 from ‘Foo’ to ‘float’ > > > > The g++ example isn't great either... but is better because of this: "no known conversion for argument 2 from ‘Foo’ to ‘float’" > > > It actually told me which argument didn't match! clang is similar: > > $ clang lll.cpp > lll.cpp:7:2: error: no matching function for call to 'foo' > foo(0, Foo()); > ^~~ > lll.cpp:1:6: note: candidate function not viable: no known conversion from 'Foo' to 'char *' for 2nd argument > void foo(int a, char* b); > ^ > lll.cpp:2:6: note: candidate function not viable: no known conversion from 'Foo' to 'float' for 2nd argument > void foo(int a, float b); > > > > With the dmd one, especially on a long function, it is hard to tell just which argument is giving trouble. The C++ errors just flat out tell me which argument didn't match for each candidate. In this simple case above, I actually prefer DMD's messages, as there's simply less text for my eyes to read and brain to parse, so I can quickly spot where the problem is. I agree, though, that with longer argument lists, especially with const vs. non-const or template constraints, trying to figure out what's wrong could be at least frustrating. > Templates with constraints are even worse. > > lll.d(3): Error: template std.algorithm.sorting.sort cannot deduce function from argument types !()(int), candidates are: > /home/me/d/dmd2/linux/bin32/../../src/phobos/std/algorithm/sorting.d(1830): std.algorithm.sorting.sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r) if ((ss == SwapStrategy.unstable && (hasSwappableElements!Range || hasAssignableElements!Range) || ss != SwapStrategy.unstable && hasAssignableElements!Range) && isRandomAccessRange!Range && hasSlicing!Range && hasLength!Range) > > > What a mess! Just formatting that output might help, but I'd especially love it if it told me which individual boolean elements failed, passed, and were short-circuited. The compiler knows this, it had to evaluate that to figure out it didn't match, but it doesn't tell me. > > At a glance, can you even tell what I passed to the function? > > Bonus points would be it telling me why, for example, `isInputRange` failed, but I understand that is an even bigger problem to solve. It's indeed painful, but I found UDAs to be useful in dealing with it. First, I'm sure you know Atila's concepts [1]. I also use UDAs in flod [2], so instead of checking whether the implementation satisfies a constraint, I only check if it's explicitly tagged with a specific UDA. Now, I immediately see whether it's a method that I forgot to implement or just a typo, instead of being forced to guess by a "missing overload" message. > > Of course, C++ doesn't have constraints so there's no comparison there. > > > Lastly, check this out: > > lll.d(5): Error: function lll.foo (Color c) is not callable using argument types (Color) > > WTF, right? Well, I have a locally defined `struct Color` and an imported one. Same name, but different type. The error message doesn't tell me which one is which. Yeah, that one was funny. :) > These are the top 3 dmd error messages that bother me regularly. At runtime, little drives me more nuts than RangeError not telling me the index and the length. Again, it knows, the code checked it, but it didn't report it. Same with assertions. I usually end up adding wrappers like assertEqual, and the more I use them, the more I feel like switching to something like [3] or [4], as much as I normally prefer to keep the number of dependencies low. I think RangeError could be solved without much effort by changing the compiler/runtime interface at _d_arraybounds*. Assertions are probably harder. [1] http://forum.dlang.org/post/eoxerbkaowxpgjubhdqq@forum.dlang.org [2] https://github.com/epi/flod/blob/develop/source/flod/package.d [3] https://code.dlang.org/packages/fluent-asserts [4] http://code.dlang.org/packages/unit-threaded |
May 10, 2017 Re: "I made a game using Rust" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adrian Matoga | On 05/10/2017 11:50 AM, Adrian Matoga wrote: > On Wednesday, 10 May 2017 at 15:03:19 UTC, Adam D. Ruppe wrote: >> >> lll.d(5): Error: function lll.foo (Color c) is not callable using >> argument types (Color) >> >> WTF, right? Well, I have a locally defined `struct Color` and an >> imported one. Same name, but different type. The error message doesn't >> tell me which one is which. > > Yeah, that one was funny. :) It's not so funny when you're new to that error and don't already know to look for two types from different modules with the same name. :( > Same with assertions. I usually end up adding wrappers like assertEqual, > and the more I use them, the more I feel like switching to something > like [3] or [4], as much as I normally prefer to keep the number of > dependencies low. > > [3] https://code.dlang.org/packages/fluent-asserts > [4] http://code.dlang.org/packages/unit-threaded Unit-threaded rocks my world. First I've heard of fluent-asserts but it looks interesting. |
May 10, 2017 Re: "I made a game using Rust" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adrian Matoga | On Wednesday, 10 May 2017 at 15:50:06 UTC, Adrian Matoga wrote: > In this simple case above, I actually prefer DMD's messages, as there's simply less text for my eyes to read and brain to parse, so I can quickly spot where the problem is. Well, even here, I'd prefer a small tweak: lll.d(6): Error: none of the overloads of 'foo' match given: foo(int , double) lll.d(1): lll.foo(int a, int a) lll.d(2): lll.foo(int a, string s) The alignment would make it easier to eyeball the matches and options... though that fails on longer lines too. Another option is using colors (or something) to highlight which ones in the candidates matched and which didn't. The difference is small in a short case like this... but even here, I'd call it slightly better, and in a big case, it is much better. > It's indeed painful, but I found UDAs to be useful in dealing with it. Oh, that's on the declaration side, but this error message is on the call side. Suppose I pass an input range to sort(). I prove it is an input range with UDAs or static asserts or whatever, yet the call to sort fails. Why? It is because sort requires more than just an input range, but just whate is difficult to determine from the error message. So a legible error message tells you WHAT you need to test on the declaration ("must be random access"), then the udas can handle those error messages (so like "it is not a random access range because opIndex is not implemented") Of course, the sort() function could check `isSortable` instead of everything it lists in its constraint... and I think I'd like that, but still, a more readable error message would be a big win. The llvm people are just annihilating us in the error messages and that's a bigger day-to-day boost than it seems. So yeah, we should do both: make the decls nicer with UDAs, but also make the error messages nicer for all cases. oh another class of error messages that suck: "@nogc function cannot call non-@nogc function map". but map is inferred so why did it fail? wrote this up in bugzilla: https://issues.dlang.org/show_bug.cgi?id=17374 > I think RangeError could be solved without much effort by changing the compiler/runtime interface at _d_arraybounds*. Assertions are probably harder. yeah, I actually tried to implement it one time and failed though - the compiler code is a bit more fragile than I thought. Still shouldn't be too hard, if I had a few hours to spend on it I could prolly do it. |
May 10, 2017 Re: "I made a game using Rust" | ||||
---|---|---|---|---|
| ||||
Posted in reply to JN | On Wednesday, 10 May 2017 at 12:52:34 UTC, JN wrote:
> I wonder, would it be possible for D in the current state to achieve the same? I imagine iOS isn't possible yet and Android is just getting there?
Reading this thread while going through the online D book I wonder;
Would one recommend D for gamedev? I was thinking of writing small games with the help of SFML to learn D better and try to get better at programming game logic(DLang is my second programming language).
|
May 10, 2017 Re: "I made a game using Rust" | ||||
---|---|---|---|---|
| ||||
Posted in reply to JN | On Wednesday, 10 May 2017 at 12:52:34 UTC, JN wrote: > Interesting thread I got from Reddit, someone made a game for PC and mobiles fully in Rust. > > https://michaelfairley.com/blog/i-made-a-game-in-rust/ > > "Last week, I released A Snake’s Tale on iOS, Android, Windows, Mac, and Linux.". > > I wonder, would it be possible for D in the current state to achieve the same? I imagine iOS isn't possible yet and Android is just getting there? iOS is possible, though that cross-compiler hasn't been updated in a year: https://github.com/smolt/ldc-iphone-dev/releases Cross-compiling for Android has been available for awhile, and I got JNI working late last year: https://github.com/joakim-noah/android/releases That game programmer mentions wanting more control over optimizing methods in Rust. Funnily enough, I've been messing with pragma(inline, true) just today to track down a bug related to inlining, and Johan added an attribute called optStrategy to ldc last summer, which lets you selectively turn on or off optimizations for a method: https://github.com/ldc-developers/ldc/pull/1637 Radu used it when debugging ldc on an ARMv5 microcontroller recently. Not available standardized across D compilers obviously, but could be some day. |
May 10, 2017 Re: "I made a game using Rust" | ||||
---|---|---|---|---|
| ||||
Posted in reply to JN | On Wednesday, 10 May 2017 at 12:52:34 UTC, JN wrote:
> I wonder, would it be possible for D in the current state to achieve the same? I imagine iOS isn't possible yet and Android is just getting there?
I've been developing a small 2D PC-only game in my free time over the last year or so (10 kLOC so far). It's very much still in the early stages, but I'll add some of my experiences here in case it's useful.
For context, I'm a developer of 2.5 years at a medium-sized studio that ships full-price games. At work we use C++ (msvc) for the engine, Lua for scripting, and C# for tools.
TLDR: You can totally make a game in D right now. However, it's definitely not ideal. Be ready to deal with untested tools/libraries, wrangling with how you call out to C libraries, and a couple hacks to the D source to make things work the way you want.
PROS
I'll skim this section, because you all know the pros of D at this point :) No header files, sane templates, way better introspection, the list goes on. D is one of the nicest programming languages I've had the pleasure of working in. It's not without its faults, but my experience so far is that it's the language I most want to be developing a game in right now. We'll see if Jai might take that throne some day, but I reserve judgement until I can actually get my hands on it, and even that might still be years out.
The Rust article mentions build times as a downside. In contrast, that has been one of the upsides of D for me. My build time is ~1.75s for a usual-case rebuild (all the game files), and ~4.5s for a full rebuild (the game, plus all heavy templates (like regexes), and all library glue code (like derelict)). Rapid build times are one of the killer features of DMD, and it makes me happy to know it will continue to be a focus as development continues.
CONS
The debugger. Rainers is doing great work with Mago, I suspect it simply needs more developers giving it some love. It's currently a far cry from the MSVC debugger. Mago crashes/hangs regularly for me, doesn't step in and out of functions consistently (and you can't reposition the instruction pointer by dragging if you miss a function call you want to re-run), is inconsistant about which variables I can see and which I can't, and lacks features I miss greatly (like data breakpoints). This is *by far* my biggest pain point. I'd like to look at it at some point and try to improve some of the low-hanging fruit, but debugging a debugger is a daunting proposition.
DLL support. I've made a handful of hacks to druntime to allow me to implement hot-reloading via a DLL (a la Handmade Hero). My problems all stem from the fact that a D DLL has its own copy of the runtime and GC. I use the GC proxy to redirect calls from the DLL's GC to the EXE's GC, and have hacked together a similar solution for redirecting the spawning of threads. On top of that I had to completely disable finalizers, and pretty much avoid using classes altogether (at least any that might need to outlive a frame or survive a hot reload). I'll bet it's no easy task to implement, but if D supported "light" DLLs (ie DLLs that just work out of the executable's druntime), probably 2/3 my hacks to
D would evaporate. This all being said, the hot reloading works marvellously with these changes, and it combined with a <2s build time makes day-to-day development far more of a joy than at work.
The GC. This is an issue in games for reasons already tread many times over. It's lower on my list because it's relatively straightforward for me to intercept GC calls and do my own memory management instead. I've hacked in a setup that lets me swap allocators at runtime. For example, I can add a line at the top of a scope that says "for the duration of this scope, allocate into the scrapheap" (a bump-the-pointer stack that gets wiped at the end of each frame). I currently use the GC by default, and manually specify an allocator to use anywhere I'm generating excessive garbage, but this strategy will likely change as development continues and performance constraints start becoming more strict.
Library support. Basically the same as mentioned in the Rust article. I regularly try out libraries where I find a critical bug within an hour of using the library. I've used libraries (plural) that interface to C but use the wrong calling convention, so before I discovered the problem, every function I called was a crapshoot as to whether or not some subtle misbehaviour or outright crash would occur.
For reference, the libraries I'm using are:
- SFML (graphics/windowing, misc utilities)
- FMOD (audio)
- dear imgui (debug UI)
- msgpack-d (save game/state serialization)
- OpenGL (just tiny bits here and there for stuff SFML and imgui don't handle out of the box)
- speech4d (TTS for placeholder dialogue, I heavily modified this library to fix some critical bugs and make it work better for my purposes)
Any questions, ask away!
|
May 10, 2017 Re: "I made a game using Rust" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ethan Watson | On 5/10/17 10:37 AM, Ethan Watson wrote: > On Wednesday, 10 May 2017 at 14:31:28 UTC, Vladimir Panteleev wrote: >> Internal compiler errors (ICEs) are bugs which are generally treated >> as high priority. Please report them. > > See my previous rant on this subject. > > http://forum.dlang.org/post/qkxyfiwjwqklftcwtcik@forum.dlang.org And my previous answer: http://forum.dlang.org/post/nqc4tg$12im$1@digitalmars.com I'll reiterate here: if the compiler's sanity is suspect, there's nothing much for it to do except crash. hard. And tell you where to look. Fortunately for the current state of affairs, if the error is in the front-end, it's D. And it should give you a stack trace. Your previous example seems to be in C++ part of it, so no stack trace. -Steve |
May 10, 2017 Re: "I made a game using Rust" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Wed, May 10, 2017 at 07:52:53PM -0400, Steven Schveighoffer via Digitalmars-d wrote: [...] > I'll reiterate here: if the compiler's sanity is suspect, there's nothing much for it to do except crash. hard. And tell you where to look. [...] OTOH, it's not very nice from a user's POV. It would be nice(r) if this PR could be looked at and brought to a mergeable state: https://github.com/dlang/dmd/pull/6103 T -- Programming is not just an act of telling a computer what to do: it is also an act of telling other programmers what you wished the computer to do. Both are important, and the latter deserves care. -- Andrew Morton |
May 11, 2017 Re: "I made a game using Rust" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Lewis | On Wednesday, 10 May 2017 at 22:13:29 UTC, Lewis wrote: > On Wednesday, 10 May 2017 at 12:52:34 UTC, JN wrote: > > PROS > > > The Rust article mentions build times as a downside. In contrast, that has been one of the upsides of D for me. My build time is ~1.75s for a usual-case rebuild (all the game files), and ~4.5s for a full rebuild (the game, plus all heavy templates (like regexes), and all library glue code (like derelict)). Rapid build times are one of the killer features of DMD, and it makes me happy to know it will continue to be a focus as development continues. I have played recently with one D game engine and result was frustrating. My compile time was about 45 sec! Engine split in core and actual game module, every time i build game module it recompiles the engine. Great compile times, yay! The engine itself is just ~12k LOC, "game" roughly 200 lines. For example UE4 project with same line count compiles within 50 secs! Of cource whole D engine takes just 20 secs on single core, while C++ project takes all my 8 cores. (and for example building whole UE4 takes almost hour on SSD) Every changed line of code triggers full rebuild in D (remember, it does this twice, one for engine, second for game). As C++ user I find it unacceptable, simply because with PCH such changes is usually takes 2-3 secs if one don't touch the headers (well okay, more like 10 secs, still twice faster than D on edit-build-debug runs). > > CONS > > The debugger. Rainers is doing great work with Mago, I suspect it simply needs more developers giving it some love. It's currently a far cry from the MSVC debugger. There is no sane x64 debugging on Windows. structs doesn't shows at all, that just top of the list... But I remember what's was back in 2011, now we at least can do full debug for x86! And last time I used OS X(in 2013) that was... well I prefer not to comment, there was simply no debugging at all. > DLL support. I've made a handful of hacks to druntime to allow me to implement hot-reloading via a DLL (a la Handmade Hero). My problems all stem from the fact that a D DLL has its own copy of the runtime and GC. I use the GC proxy to redirect calls from the DLL's GC to the EXE's GC, and have hacked together a similar solution for redirecting the spawning of threads. On top of that I had to completely disable finalizers, and pretty much avoid using classes altogether (at least any that might need to outlive a frame or survive a hot reload). I'll bet it's no easy task to implement, but if D supported "light" DLLs (ie DLLs that just work out of the executable's druntime), probably 2/3 my hacks to > D would evaporate. This all being said, the hot reloading works marvellously with these changes, and it combined with a <2s build time makes day-to-day development far more of a joy than at work. How did you managed using classes from DLL? I mean in its current state D unable to cast anything that comes through process/shared lib boundaries(except on Linux) due to missing type info, right? And this is serious issue, this is really blocks D from commercial usage, simply because there is no way to add plugin support (from user's point of view). And realistically this is also not so trivial, this requires making special 'core' library with common classes and interfaces to include in every DLL and app itself, because one would need to use both .d and compiled module .obj (for type info, that annoying unresolved _ClassZ and others) and current build systems doesn't helps with that all, so all by hand it seems... Overall, I really like D, but its like feeding on cactus... |
May 11, 2017 Re: "I made a game using Rust" | ||||
---|---|---|---|---|
| ||||
Posted in reply to zetashift | On 10/05/2017 7:20 PM, zetashift wrote: > On Wednesday, 10 May 2017 at 12:52:34 UTC, JN wrote: >> I wonder, would it be possible for D in the current state to achieve >> the same? I imagine iOS isn't possible yet and Android is just getting >> there? > > Reading this thread while going through the online D book I wonder; > Would one recommend D for gamedev? I was thinking of writing small games > with the help of SFML to learn D better and try to get better at > programming game logic(DLang is my second programming language). Well, I wouldn't be working on[0] and [1] if I didn't think D could be used for game dev. Yes it has some work to do to make it nice, but over all its workable. [0] http://spew.cf [1] https://github.com/rikkimax/ogl_gen |
Copyright © 1999-2021 by the D Language Foundation