This Week in D March 6, 2016

Welcome to This Week in D! Each week, we'll summarize what's been going on in the D community and write brief advice columns to help you get the most out of the D Programming Language.

The D Programming Language is a general purpose programming language that offers modern convenience, modeling power, and native efficiency with a familiar C-style syntax.

This Week in D has an RSS feed.

This Week in D is edited by Adam D. Ruppe. Contact me with any questions, comments, or contributions.

Statistics

Major Changes

The D Foundation was accepted for Google Summer of Code 2016. The project details are still being determined.

Dconf got a new logo ahead of the conference, which is now about two months away.

D 2.070.2 was released with a single bug fix.

In git, dmd got more refactoring work to remove preprocessor usage in the backend (a prelude to eventually converting it to D as well), and the website got a lot of missing anchors added - meaning we can now link to specific sections.

In the community

Community announcements

See more at the announce forum.

Tip of the Week

This week, I want to talk about struct subtyping and how it can work as a kind of named arguments.

My simpledisplay.d has an experimental text component which, while being far from finished, already has a single function which can do a number of things like change color, add text, or change text style attributes:

	obj.addText(
		ForegroundColor.blue, TextFormat.underline,
		"this is drawn like a link",

		ForegroundColor.black, ~TextFormat.underline,
		" and this is normal again"
	);

It achieves this through a variadic template and various specific subtypes for things like ForegroundColor and BackgroundColor, which all specialize the generic struct, Color, from arsd.color.

Here's the source of ForegroundColor:

	struct ForegroundColor {
		Color color;
		alias color this;

		this(Color c) {
			color = c;
		}

		this(int r, int g, int b, int a = 255) {
			color = Color(r, g, b, a);
		}

		static ForegroundColor opDispatch(string s)() if(__traits(compiles, ForegroundColor(mixin("Color." ~ s)))) {
			return ForegroundColor(mixin("Color." ~ s));
		}
	}

Is is a bit long for something that does very little, and if I was going to repeat it several times, I'd factor that entire body out into a mixin template, but it isn't hugely long and provides all the convenience constructors so you don't have to write ForegroundColor(Color(r, g, b, a)) at the usage site.

The opDispatch at the end succinctly forwards static methods to the same on Color, enabling usage of those convenience factories too, such as ForegroundColor.white instead of ForegroundColor(Color.white).

However, those constructor and opDispatch lines are not strictly necessary to demonstrate the subtyping pattern, which is provided by just the first two lines, notably, alias this.

alias this just forwards unknown methods on an extant object to a member, and will also yield said member when the object is used in a context where the submember's type is requested. In other words, it will allow the outer member to implicitly convert to the inner member where context requires it.

I said "extant object" because the object needs to already be created before alias this will take effect. That means you can NOT use alias this to forward constructors, nor to do implicit construction when calling an object: void foo(ForegroundColor color) {} Color color; foo(color); // will NOT compile. alias this does not do construction.

With alias this in place, any function that expects a Color can take a ForegroundColor the same (the compiler will automatically rewrite func(fg) into func(fg.color)), and any other members on Color will also work through ForegroundColor. For example, the r, g, b, and a members will be transparently available.

But, when passing it to a template, the template will still see it as ForegroundColor, not Color! Similarly, functions can overload on ForegroundColor separately than on Color (as long as the type is statically known. Unlike classes, there is no dynamic cast(ForegroundColor) on a Color possible. Remember, the compiler rewrites it into a member access - from that point on, the function just sees that one member, with no knowledge of what is holding it.).

Since functions can distinguish the difference at compile time, we can also reflect on that! Which brings us back to addText. Here is its code:

		void addText(Args...)(Args args) {
			if(blocks.length == 0)
				addBlock();

			InlineElement ie;
			foreach(idx, arg; args) {
				static if(is(typeof(arg) == ForegroundColor))
					ie.color = arg;
				else static if(is(typeof(arg) == TextFormat)) {
					if(arg & 0x8000) // ~TextFormat.something turns it off
						ie.styles &= arg;
					else
						ie.styles |= arg;
				} else static if(is(typeof(arg) == string)) {
					static if(idx == 0 && args.length > 1)
						static assert(0, "Put styles before the string.");
					size_t lastLineIndex;
					foreach(cidx, char a; arg) {
						if(a == '\n') {
							ie.text = arg[lastLineIndex .. cidx];
							lastLineIndex = cidx + 1;
							blocks[$-1].parts ~= ie;
							ie.text = "\n";
							blocks[$-1].parts ~= ie;
							addBlock();
						} else {

						}
					}

					ie.text = arg[lastLineIndex .. $];
					blocks[$-1].parts ~= ie;
				}
			}
		}

Ignore many of the specifics and just look at the general shape of the function:

	void addText(Args...)(Args args) {
		foreach(arg; args) {
			static if(is(typeof(arg) == Something)) {

			} else static if /* ... */ {

			}
		}
	}

You can loop over variadic arguments (sometimes called tuples or AliasSeqs) with foreach and inspect the type of each argument individually and react accordingly.

addText uses a combination of type analysis and value checking to determine its action. If it sees a plain style, it turns it on. An inverted style (~TextFormat.underline, for example, with the unary ~ acting to invert the bit pattern) turns that style off. If it sees one of the specializations of Color, it uses the type to know if it should change the foreground or some other color value.

You could also use this pattern in something like opAssign or some other property to act based on assigned types.

This pattern could also be done with a list of function overloads, but the loop is easier to handle more combinations:

	void addText(ForegroundColor color, string text) {}
	void addText(BackgroundColor color, string text) {}
	void addText(ForegroundColor color, BackgroundColor bg, string text) {}
	void addText(ForegroundColor color, BackgroundColor bg, TextFormat fmt, string text) {}
	void addText(string text);
	// the list would go on and on and on. The loop does all this!

And the loop still uses static assert to make it a compile error if you give it something it can't handle, like text before formatting. (The way the text object works just requires formatting to be known before it attempts to draw the actual string.)

This brings me to my final point: this same pattern can be done to do something approximating named arguments, using either the loop or the overloads. By defining a specialized type for a certain piece of data, you force the call site to use that name somehow, giving the documentation of named params along with some type safety too. With overloads or looping, you can take them in arbitrary orders, including with required, optional, or default values.

	struct Size { int w; int h; }
	struct Point { int x; int y; }

	struct PointUpperLeft { Point p; alias p this; this(int x, int y) { p = Point(x, y); } }
	struct PointLowerRight { Point p; alias p this; this(int x, int y) { p = Point(x, y); } }

	drawRectangle(Point(0, 0), Size(10, 10), ForegroundColor.red);
	drawRectangle(PointUpperLeft(0, 0), PointLowerRight(10, 10), ForegroundColor.red);

	// and so on with other combinations which makes it clear as opposed to

	drawRectangle(0, 0, 10, 10, 255, 0, 0); // what does each number mean?
	// is it lower right point, or width and height?

Writing the structs for the various names takes a small amount of work, though with mixin templates you could automate most of it, but regardless, the benefit for your users can be significant.

Learn more about D

To learn more about D and what's happening in D: