July 18

There are special keywords that decay into context-dependent strings or values, e.g. __FILE__ and __LINE__ which can be used as default arguments and make logging a breeze.

For asserting, it would be nice to have access to the expression that was asserted on.

My idea was to add __EXPRESSIONS_OF__ which decays to an array literal that contains the tokens as strings of selected function arguments. There’s two ways it can be used:

  • __EXPRESSIONS_OF__(comma-separated Identifiers) to refer to (named) arguments.
  • __EXPRESSIONS_OF__(comma-separated ConditionalExpressions) to index (0-based) into the arguments. Of course, the number must be less than the number of arguments passed. (The ConditionalExpression must evaluate to an integer at compile-time.)

Of course, if the list is of known length (which in ordinary code, it is), the resulting literal can be bound to a fixed-size array. As an example:

void myAssert(bool condition, lazy string message = "assert failed: ", string[1] expression = __EXPRESSIONS_OF__(condition))
{ … }

The by-index referral is intended to make meta-programming easier, to have support for the case where the parameter isn’t really named (for whatever reason, which there are many, from linters not liking named parameters that aren’t used, to expansion of compile-time sequences).

The result is available at compile-time and can be bound to a template argument:

void someTemplate(Ts..., Es = __EXPRESSIONS_OF__(args))(Ts args) { … }
void someTemplate(Ts...)(Ts args, string[1] expr = __EXPRESSIONS_OF__(0)) { … }

What do you think?

To a limited extent, it can be replicated using alias template parameters:

void assertEquals(alias value, T)(T expected)
{
    if (value != expected)
    {
        import std.stdio;
        writeln(value.stringof, " had an unexpected value: ", value, " != ", expected);
    }
}

void main()
{
    int x = 10;
    assertEquals!x(10); // silent
    assertEquals!x(11); // prints: x had an unexpected value: 10 != 11
}

However, that only works with identifiers.

July 18

On Tuesday, 18 July 2023 at 13:33:49 UTC, Quirin Schroll wrote:

>

To a limited extent, it can be replicated using alias template parameters:
[...]
However, that only works with identifiers.

The general-case replacement for this is a string mixin:

string myAssert(string condition, string message = "assertion failed: ")
{
    return `assert(` ~ condition ~ `, q"(` ~ message ~ condition ~ `)");`;
}

void main()
{
    mixin(myAssert("2 + 2 == 5"));
}