importC released, preview of arsd web, database, gui updates, phobos2 coming, dual context tip of the week

Posted 2021-11-01

Several things: importC first use, web, database, gui updates in arsd, phobos2 might happen, dual context tip of the week.

Core D Development Statistics

In the community

Community announcements

See more at the announce forum.

ImportC is out

And it doesn't just work out of the box. You need to add an extra step the documentation doesn't mention. Iain sent me a list of #define statements you can include in your file to make it all work. They translate things like __restrict to restrict; that is, turn vendor extensions into standard keywords that the dmd parser understands. Then you still run through the external C preprocessor and you have a file.

After that, I was able to compile a hello world using it with D.

The problem is, of course, that preprocessor macros are a necessary part of virtually any C library and there's still no answer for that. I wrote a short, half-baked article with an idea to fix this:

http://dpldocs.info/experimental-docs/mixinc.html

In short, it'd integrate a preprocessor, not just to C, but also to D itself, so you can create a context and pass it in to a kind of mixin, not just import. This lets you use it in API usage points as well; with this you can kinda mix C and D, without breaking D with the preprocessor. I'm not 100% happy with that, but I do think I have a viable path there. And then you can reflect on it too to do things like bridge certain macros directly into D (like what dstep does).

We should talk about it.

Phobos 2 might actually happen

Andrei Alexandrescu is excited about a template concept he played with over the weekend to version imports while reusing some code.

While I'm not sure this approach will actually be worth it as we get into the work, I'm still happy something is actually happening. Well, ok, things have looked like they were moving along before, so I shouldn't get too excited too soon. But Andrei is one of the biggest heavy-hitters behind Phobos and has the political clout to make changes, and this scheme appeases his own concerns about compatibility.

So I think there's a good chance we'll get something. Even if the approach ultimately needs to adjust as it doesn't fit everything, once the ball is rolling we'll be ahead.

I expect I'll add some custom features to adrdox to help with this process too, so stay tuned to here to see those as they happen.

Tip of the Week

Andrei asked me for help with a dual-context problem that happened while he was working on that. The answer: static.

When you see a dual-context thing, try making the function you are calling static. That might solve it automatically - the compiler often thinks there's a problem where there isn't one and this hint gets it back under control.

When you can't go static, you might be able to manually combine contexts. This often comes with a closure that is also accessing the this pointer of a class. You can work around this by just making a local variable auto this_ = this; and using that instead. The compiler usually can figure this out for you so it is rare to need to do it yourself, but this technique is sometimes needed.

And remember when you do make a function static and want to pass in an object, another thing you can do is just pass the this as an argument. If the this is a struct btw, you almost certainly want to do this instead of taking an automatic delegate anyway since structs can be moved and invalidate that address without telling you. Just make it an explicit argument and pass it when needed.

It is hard to make an example to demo these because the compiler often does figure it out automatically, but if you see a dual-context problem, try these tricks and odds are you can work past it, despite the compiler giving up on you.

What Adam is working on

web and database

Two weekends ago, the folks who run a game I sometimes play said they were looking for a new website to play their bingo variant, saying the old one didn't quite give they customization they wanted. I said "oh that's a weekend job" and set out to prove it. Indeed, I got the basic functions working in just about a day by reusing some old code I had written for a similar game previously.

Well, now I want to clean it up and post it, so I spent some time on it last weekend too. Now that I've done a few little projects with the new cgi.d facilities, a few patterns are emerging and I'm able to move some of those patterns to the library itself, and I'm finding some of my old code is useful for it too.

I'm going to write about this at more length next week, once I finish the cleanup and can show you the live demo, but a sneak preview here:

  • The EventSourceServer makes distributing real-time updates trivially easy. It is about three lines of code. However, the browsers refuse to lift their connection limit for EventSource so I might have to add a bit of websocket adapter too for those case. I'm pretty sure I can continue to do that 100% in the library, meaning it is still just three lines to distribute updates to subscribed listeners.
  • The ApiObject together with my webtemplate's mixin templates make doing html files together with auto-generated facilities very easy.
  • The new DispatcherMain uses a generated main for boilerplate url dispatching. Of course, you can still call the functions yourselves in order as things get more complicated. (That's the big reason for much of this design: I want it easy for simple things but still flexible for cases where you must break outside the box.)
  • Some old code from 2011 and 2014 in my database.d turned out to be easy to adapt to my RestObject. I just made one more mixin template for the boilerplate:
    class Employee : RestObject!(Employee) {
    	// implement the data members as plain old data
    	// the annotation is actually for my database helpers
    	// rather than the web code but eh it works nicely together.
    	@DbSave {
    		int id;
    		string name;
    		string title;
    		int salary;
    	}
    
    	mixin DatabaseRestObject!(() => new PostgreSql("dbname=test"));
    }

    Boom, automatic forms, automatic database, automatic json.

Exciting stuff! More next week as I need one more weekend to turn my functional, but raw, code into the beautiful shareable demo. I'll also write up details about how it works and what to do when you must break out of the box.

gui

I added a param to SimpleWindow.impl.motifHideDecorations so you can turn it on or off now. The members inside impl are generally not documented and subject to change, but I do try to maintain them anyway since they are useful for people doing lower level or platform-specific work.

Sometimes the code is helpful for people wanting to learn about this too, as the low level functions in Linux are frequently poorly documented.

Speaking of poorly documented functions, I finally got XRender's gradient functions (XRenderCreateLinearGradient, XRenderCreateConicalGradient, etc.) to work. I knew you had to multiply fractional values by ushort.max, but I assumed integers didn't need that (and the docs never said...), but they also need it. So you should always multiply values by ushort.max there. Now I know. But I might use this for a bit of decoration in minigui's default linux themes since I can do it efficiently now (I use remote X links a lot and sending images is not one of its strengths. Many toolkits ignore this and give X a bad name. X... partially deserves it - if it supported png and jpg this wouldn't be as big of a deal - but if you write your code knowing this you can still do a good job.) I will consider adding gradient brushes to the screenpainter now.

XLinearGradient gradient;
// from (0, 0) to (100, 100) on screen:
gradient.p1 = XPointFixed(0, 0);
gradient.p2 = XPointFixed(100 * ushort.max, 100 * ushort.max);

// from 0% to 100% of the size
XFixed[2] stops = [0, ushort.max,];// 2 * ushort.max / 4, 3 * ushort.max / 4, ushort.max];
XRenderColor[2] colors = [
	// no premultiplied alpha here, but values are 0-ushort.max, so do a float between 0 and 1.0 then times ushort.max.
	XRenderColor(ushort.max, 0, 0, 64 * 255),
	XRenderColor(0, ushort.max, ushort.max, 255 * 255),
];

auto fill = XRenderCreateLinearGradient(
		XDisplayConnection.get,
		&gradient,
		stops.ptr,
		colors.ptr,
		cast(int) stops.length);

// snip. Though I might edit in more code later cuz the search
// results were painful.

I also just fixed a regression introduced to minigui's layout engine a few months ago that could lead to label text being cut off at times.

Coming soon

I have a request to integrate remote input to a terminal.d event loop. Some of the pieces are there but it is incomplete. I'll have to figure out something in the next few weeks. I'm still considering adding a module... we'll see.