I did a dconf livestream!

Posted 2020-11-23

I did a livecoding session for DConf on Saturday, the 21st. Didn't quite go as planned, but was good nonetheless.

Core D Development Statistics

In the community

Community announcements

See more at the announce forum.

DConf Online 2020

Looking back

I've personally participated in DConf twice before but haven't for some time due to my dislike of travel. Thus, when DConf Online was announced, I was maybe willing to do it and sent an email to the organizers saying I could do something live.

Well, they put my on the schedule and with a little ffmpeg magic, and a false start to reset it, it connected and I was live.


I had to change my terminal emulator to use a larger font so people could see it clearly, but since I did the simpledisplay font overhaul earlier in the month, it worked out! (Of course, I had an image-based ttf renderer before - one based on XImage and one based on OpenGL, with my arsd.ttf module, but now it was easier and better for this.)

Well, I wrote about 50 lines of the program ahead of time, so when I got on, I built up from that fairly early and pretty quickly had the ship drawing on screen. But as people asked about my window manager, text editor, and other things, I got distracted and went gabbing on many digressions. Frequent readers of this blog may already have an idea, but being able to show it off live, with full video, was fairly amusing, I almost wish I planned to just do that!

Around the half-time point, I realized I needed to get back on topic. I carried on with the creation and showed off part of how the libraries work and an addition to the webassembly version. The biggest mystery is when I went to add bullets, they didn't show up! After some confusion, I decided to just move on and go to the network bit instead.

In the end, I got it working so multiple people could log in and issue commands... but all to different displays of the same ship. So it mostly just spun wildly and wasn't much of a game to play when I ran out of time. While the DConf organizers scheduled me at the end so I could go late if I wanted to, I preferred to stay on time (and besides, it was my birthday and I had cake to eat!)

Shortly after disconnecting, I looked at the bullet code again and realized the problem: I just didn't initialize one of the functions. See, I wrote:

struct GameObject {
	float x, y, a;
	float dx, dy, da;

Among some other things. The update would add the d* to the corresponding value, then to draw, it would be r * sin(a).

Well, I wrote objects ~= GameObject(0, 0, 0, 0, 0); ... see the problem? I left a value out and thus got default initialization: NaN.

Then a += da set it to NaN as well... then drawing got sin(NaN) and thus there was nothing to draw. In the livestream, someone was like "print out the vertexes!" but I only looked at the initial values of x, y, not the final values. And I missed it until the end.

This could have been prevented with a few options:

1. I could have written a constructor on the struct. Then missing arguments would be flagged as a compile error. I didn't think to do this since plain-old-data has a built in constructor that works well enough, but perhaps it would have been a better idea anyway.

2. The compiler actually issues an error when you use an uninitialized variable. Pretty sure this is actually allowed by the D spec, but no compiler actually does... and people rely onthis now.

3. I could have written = 0 on each member. This is a good idea because it also avoids the struct init static data, makes linking easier (if you import a header lib referencing extern(C) functions and get some missing init member when you don't compile it in, it is probably because it has a struct with a char or float in it.

4. The compiler could do #3 for me. See, the idea behind D's initialization is it catches uninitialized values at runtime. Null pointers crash. NaN floats give NaN results. \ff chars give invalid strings.

The problem is it sets the initializer for int (and friends) to be 0. Which is actually pretty useful and convenient, so people rely on it. Now making uninitialized things an error is infeasible and the fact is it sets a habit to expect 0.

So I think we should embrace that. Just change the initializers to be all 0 by default. Then you don't need init blobs anymore (unless the user specifies something). Just zero allocate it and don't bother touching all the memory. Faster, easier, and really, no less correct than it is now.

Of course, after having been bit by this so recently, next time I see something similar, I'll surely remember to check for NaN faster. But since it wasn't on my mind live, the error was just mysterious. I thought I wrote a bad shape definition or did the drawing function wrong, or even a bug in my webassembly runtime (though I was testing under Linux, my brain was split at the time). A compile error at least calls it out... a segfault happens fairly quickly and is kinda obvious. But NaN propagation isn't as immediately obvious.

char's default isn't as bad but still, a zero is better. We should just change the language.

Looking forward

I might do another stream in a little while to finish the game and probably do more live chat showoffs. I bunch of people liked the tweet and one suggested aiming for another Saturday about the same time as the dconf thing. I can do that.

I haven't set a date yet, but keep in touch and I'll let you all know at least a few days in advance.