Thread overview
Template elegance?
Jun 03, 2015
David Monagle
Jun 03, 2015
anonymous
Jun 03, 2015
David Monagle
June 03, 2015
Hi guys,

I was hoping some of you more experience D guys could educate me on this one.

Given the following code:

///////

// Template function

bool shouldValue(alias operation, string description, E, V)(lazy E expression, V value, string name="Value", string file = __FILE__, typeof(__LINE__) line = __LINE__) {
	if (operation(expression, value)) return true;
	throw new FeatureTestException(format("%s should %s %s, but was actually %s", name, description, value, expression), file, line);
}

// Utility functions that use the above template

bool shouldEqual(E, V)(lazy E expression, V value, string name="Value", string file = __FILE__, typeof(__LINE__) line = __LINE__) {
	return shouldValue!((e, v) => e == v, "equal")(expression, value, name, file, line);
}
	
bool shouldBeGreaterThan(E, V)(lazy E expression, V value, string name="Value", string file = __FILE__, typeof(__LINE__) line = __LINE__) {
	return shouldValue!((e, v) => e > v, "equal")(expression, value, name, file, line);
}

///////

The above works just fine. If I call something like:

value.shouldBeGreaterThan(5)

I get the expected results.

What I was looking for is a more elegant way of defining those secondary functions. Originally I was hoping I could do something like:

enum shouldEqual(E, V) = shouldValue((e, v) => e == v, "equal", E, V);

But that doesn't work as any call to result.shouldEqual(5) does results in the template being called with no TEMPLATE parameters. I understand this, however I was hoping there was a nice way of defining this functionality. I concede that my code above may already be as short and concise as I can get it.

Thanks in advance!

David.
June 03, 2015
On Wednesday, 3 June 2015 at 09:10:22 UTC, David Monagle wrote:
> What I was looking for is a more elegant way of defining those secondary functions. Originally I was hoping I could do something like:
>
> enum shouldEqual(E, V) = shouldValue((e, v) => e == v, "equal", E, V);

Here you go:
----
template shouldValue(alias operation, string description)
{
    bool shouldValue(E, V)(lazy E expression, V value, string name="Value",
        string file = __FILE__, typeof(__LINE__) line = __LINE__)
    {
        if (operation(expression, value)) return true;
        throw new Exception(format("%s should %s %s, but was actually %s",
            name, description, value, expression), file, line);
    }
}

alias shouldEqual = shouldValue!((e, v) => e == v, "equal");
alias shouldBeGreaterThan = shouldValue!((e, v) => e > v, "be greater than");
----

The trick is to split `shouldValue` into two nested templates.

The outer template has those parameters that cannot be deduced: `operation` and `description`.

The inner template has the parameters that should be deduced: `E` and `V`.
June 03, 2015
Wow, thanks very much anonymous. I did try that as a solution but stupid me was using an enum rather than an alias for the "shortcut" functions.

Been staring at the problem for so long that I couldn't see the problem right in front of me!

Appreciate the help greatly. Code now looks elegant again.