48 hour game jam

H. S. Teoh hsteoh at quickfur.ath.cx
Mon Oct 15 10:12:21 PDT 2012


On Mon, Oct 15, 2012 at 06:37:06PM +0200, Peter Alexander wrote:
> On Monday, 15 October 2012 at 15:01:27 UTC, Manu wrote:
> >
> >But mainly it's all the little things, conveniences that add up and
> >make the experience more enjoyable.
> 
> I find this as well.
> 
> D has a lot of neat and interesting features, but really the big
> advantages over C++ (for me) are:
> 
> - No header files
> - Closures
> - Polymorphic lambdas

Yeah closures are a major necessity in any modern language. Recently
I've had to work with some code that was greatly simplified because I
could simply return closures. Writing the same code in C++ or C would
have required horrendously more code and complexity.

I also found std.algorithm and std.range to be incredibly powerful in
expressing common sequential operations in a concise way, often as
one-liners where in C++ you'd have to manually write a for/while loop
with manually-managed indices, increments, loop termination conditions,
etc..

Writing custom structs/classes to conform to the range API also makes it
possible to pass things around to library code that expect ranges,
greatly eliminating lots of boilerplate code that would be needed in C++
to transcribe from one object list to another and back, ad nauseum.


> - Aliases
> - Simple(r) templates

The biggest advantage of D templates is that the syntax is actually
sane!!  When I was coding in C++, my eyes started to glaze over as soon
as templates get nested more than 2 levels deep. Especially when a
compiler error message contained a single template name that spanned 16
lines of output.  Not fun.


> The biggest problem with D at the moment for me is the quality of
> error messages, especially when using templates with constraints.  The
> best error you'll get is "can't call this function with these
> arguments", and you have to go through and manually expand the
> templates in your head to see what went wrong. Not fun.
[...]

I've asked before for a "catch-all" template, which is a template that
will be selected only if no other template is matched. This can then be
used in library code to print a nicer error message than the current
situation where the compiler basically talks to you in Klingon.

One alternative I've thought of (and tried before on one occasion) is
that instead of writing:

	RetVal MyTemplateFunc(T)(T args...) if (Condition1) {...}
	RetVal MyTemplateFunc(T)(T args...) if (Condition2) {...}
	RetVal MyTemplateFunc(T)(T args...) if (Condition3) {...}

One could write:

	RetVal MyTemplateFunc(T)(T args...)
	{
		static if (Condition1) { ... }
		else static if (Condition2) { ... }
		else static if (Condition3) { ... }
		else static assert(0, NiceErrorMsgOnWhyConditionsDidNotMatch);
	}

To be even more helpful, one could expand the static assert into a
block:

	... else
	{
		pragma(msg, "Template conditions failed:");
		pragma(msg, "Condition1 Clause1 = ", Condition1_clause1);
		pragma(msg, "Condition1 Clause2 = ", Condition1_clause2);
		pragma(msg, "Condition2 = ", Condition2);
		...
		static assert(0);
	}

Something like this is probably the compiler's job, but one could
present the info in a more human-understandable way, for example:

	RetVal MyTemplateFunc(S,T)(S s, T t)
	{
		static if (isInputRange!S)
		{
			static if (isForwardRange!T)
				...
			else static assert(0, "t must be forward range when s is output range");
		}
		else static if (isForwardRange!S)
		{
			static if (isOutputRange!T)
				...
			else static assert(0, "t must be output range when s is forward range");
		}
		else ...
	}

Of course, effort needs to be invested to write code in this way in the
first place. As a baseline, it's probably still better to have the
compiler print out exactly which conditions failed to match (by
recursively expanding templates for you). The output will be very
verbose, though.


T

-- 
MACINTOSH: Most Applications Crash, If Not, The Operating System Hangs


More information about the Digitalmars-d mailing list