Compile-Time Interfaces (Concepts)

Vlad Levenfeld via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Jul 20 17:58:05 PDT 2014


On Sunday, 20 July 2014 at 15:45:37 UTC, Atila Neves wrote:
> On Thursday, 17 July 2014 at 22:52:37 UTC, Justin Whear wrote:
>> On Thu, 17 Jul 2014 22:49:30 +0000, Nordlöw wrote:
>>
>>> AFAIK there is no compile-time variant of interfaces right?
>>> 
>>> Why is that?
>>> 
>>> Wouldn't it be nice to say something like
>>> 
>>>     struct SomeRange realize InputRange {
>>>         /* implement members of InputRange */
>>>     }
>>> 
>>> and then the compiler will statically check that that all 
>>> members are
>>> implemented correctly.
>>> 
>>> I guess this requires some new syntax to describe what an 
>>> InputRange is.
>>> 
>>> Kind of like C++ Concepts.
>>
>> What benefits would accrue from adding this?  Static 
>> verification that a
>> structure implements the specified concepts?  If so, you can 
>> simply do
>> this instead:
>>
>> static assert(isInputRange!SomeRange);
>
> This is sufficient, but not adequate. Just as the built-in
> unittest blocks with assertions, it's great when the assertion 
> is
> true but good luck finding out where the bug is when it's not.
>
> The D Cookbook has an idiom to handle this by checking for 
> __ctfe
> but it's super hacky and there should be a better way.
>
> I have lost count of how many times I wish the compiler would
> help me with compile time interfaces as it does with runtime
> code. static override and static interface? Yes please.
>
> Atila

+1, failing template constraints just gives a vague "couldn't 
match overload" type of error, and sometimes static assertions 
get suppressed. I've noticed that opDispatch is particularly bad 
about this. Even syntactic errors won't trigger compiler 
messages, and instead seems to behave like SFINAE which I was 
assured doesn't exist in D.
I have to use pragma (msg, ...) to get meaningful errors. Its so 
bad I generally avoid opDispatch despite its awesome potential 
and just generate template functions with mixins instead, because 
they are marginally easier to debug.

I wind up doing things like this to get the functionality I want:

static string assert_processing_stage_defined (string stage)()
{
	static immutable error_msg = `"Model must define processing 
stage: ` ~stage~ ` ()"`;

	return q{
		static assert (hasMember!(This, } `"`~stage~`"` q{), } 
~error_msg~ q{);
		static assert (isSomeFunction!(__traits(getMember, This, } 
`"`~stage~`"` q{)), } ~error_msg~ q{);
		static assert (ParameterTypeTuple!(__traits(getMember, This, } 
`"`~stage~`"` q{)).length == 0, } ~error_msg~ q{);
		static assert (is (ReturnType!(__traits(getMember, This, } 
`"`~stage~`"` q{)) == void), } ~error_msg~ q{);
	};
}

mixin(``
	~assert_processing_stage_defined!`initialize`
	~assert_processing_stage_defined!`update`
);

I'm sure theres worse ways to do it but I still find this ugly 
and overly specific. I would much rather use something like what 
Nordlöw suggested. Something that is standardized across the 
language and generates meaningful error messages.


More information about the Digitalmars-d-learn mailing list