September 03, 2012
On Monday, 3 September 2012 at 09:15:08 UTC, Chris Nicholson-Sauls wrote:
> On Sunday, 2 September 2012 at 23:40:01 UTC, Peter Alexander wrote:
>>
>> Consider:
>>
>> myAssert(false, "%d", 1);
>>
>> What is Args? "%d", 1 could refer to the optional arguments, or the variadic arguments. Both match.
>
> Easy: the variadic arguments are not, themselves, optional.  Match the variadic.  This kind of problem is already solved in every language with "scattering" assignments, and other such features.

The variadic arguments are optional, as you can have zero arguments count as variadic.

Also, how can I override the optional arguments in this function if all arguments are matched as variadic?
September 03, 2012
On Monday, 3 September 2012 at 09:24:42 UTC, Peter Alexander wrote:
> On Monday, 3 September 2012 at 09:15:08 UTC, Chris Nicholson-Sauls wrote:
>> On Sunday, 2 September 2012 at 23:40:01 UTC, Peter Alexander wrote:
>>>
>>> Consider:
>>>
>>> myAssert(false, "%d", 1);
>>>
>>> What is Args? "%d", 1 could refer to the optional arguments, or the variadic arguments. Both match.
>>
>> Easy: the variadic arguments are not, themselves, optional.  Match the variadic.  This kind of problem is already solved in every language with "scattering" assignments, and other such features.
>
> The variadic arguments are optional, as you can have zero arguments count as variadic.
>
> Also, how can I override the optional arguments in this function if all arguments are matched as variadic?

They are not really optional.  That the language fails to enforce this (or provide an eforcement, rather) is a shortcoming.  Pretending for a moment that D supports one of two things:

1) Empty array stands in for empty variadic.  Then, given arguments like func(R, V..., O=D) you would call it with func(foo, [], bar).  Since a typesafe variadic is effectively a sugar-laden array (well a tuple really), I see no reason this shouldn't be feasible.  First-class tuples would likely be even better.

2) Named parameters.  Then it's func(foo, O: bar), and the variadic argument can indeed be optional, although the meaning is no different than in (1).

In reality, though, we have neither of these things.  Even so, how often does this actually arise in practice (never has for me)?  And given the OP's specific case (__FILE__ and __LINE__ params) I don't foresee any useful case for overriding the defaults.

Honestly, I sometimes think that the special treatment of __FILE__ and __LINE__ when used as defaults was not the best way to go.  It might've been better implemented as hidden params, only generated by the compiler when actually used in the body.

September 03, 2012
On Monday, September 03, 2012 11:25:05 Peter Alexander wrote:
> On Monday, 3 September 2012 at 09:15:08 UTC, Chris
> 
> Nicholson-Sauls wrote:
> > On Sunday, 2 September 2012 at 23:40:01 UTC, Peter Alexander
> > 
> > wrote:
> >> Consider:
> >> 
> >> myAssert(false, "%d", 1);
> >> 
> >> What is Args? "%d", 1 could refer to the optional arguments, or the variadic arguments. Both match.
> > 
> > Easy: the variadic arguments are not, themselves, optional. Match the variadic.  This kind of problem is already solved in every language with "scattering" assignments, and other such features.
> 
> The variadic arguments are optional, as you can have zero arguments count as variadic.

You can use a template constraint if you want to require that there be at least a certain number of arguments. Also, if you know that there always needs to be at least a certain number of arguments, then you can simply make it so that the required ones are non-variadic. e.g.

void func(A, B, C...)(A a, B b, C cs)
{
    ...
}

> Also, how can I override the optional arguments in this function if all arguments are matched as variadic?

Use template constraints.

- Jonathan M Davis
September 03, 2012
On 02/09/2012 20:31, timotheecour wrote:
>>>> void myAssert(int line = __LINE__, string file = __FILE__,
>>>> Args...)(lazy bool condition, lazy Args args) {
>
> Won't that create "template code bloat" ? Ie everytime myAssert is used
> a new function is created.
...
> Another option is to use a lazy tuple argument inside myAssert instead
> of variadic arguments, which allows to pass line and file AFTER, without
> template bloat.

Do you mean:

myAssert(condition, tuple("%d", 5));

That might be useful if myAssert was more complex than just wrapping format(), but in this case it doesn't seem much better.

Peter Alexander's solution seems good, i.e. using the compile-time default arguments but with the body forwarding to a non-template function:

myAssertBody(condition, format("Assertion failed @ %s:%d: ", file, line, args));

Presumably the compiler can then optimize out each myAssert instantiation.

> A related question:
> In C++ we can stringify arguments and use it to provide informative
> asserts without duplicating code specifying a string version of the
> condition:
> #define assert( isOK ) ( (isOK) ? (void)0 :
> (void)myAssert(#isOK,__LINE__,__PRETTY_FUNCTION__, __FILE__) )
>
> Likewise for related quick debug functions:
> #define DEBUG(val) myDEBUG(#val,val)
>
> There seems to be no way of doing this currently (besides the ugly
> mixin(myAssertString("i==0")) which would parse the condition at CT).

Maybe we could have something like:

void fun(bool condition, string expr = __STRINGIFY(condition));

fun(i==0); // expr = "i==0"
September 03, 2012
On 03/09/2012 13:51, Nick Treleaven wrote:
> myAssertBody(condition, format("Assertion failed @ %s:%d: ", file, line,
> args));

Oops, that is unsafe, fixed:

void myAssert(string file = __FILE__, int line = __LINE__, Args...)(
    lazy bool condition, lazy string messageFormat, lazy Args args)
    if (args.length > 0)
{
    myAssertBody(condition,
        xformat("Assertion failed @ %s:%d: %s", file, line, xformat(messageFormat, args)));
}


September 03, 2012
On Monday, 3 September 2012 at 11:17:39 UTC, Chris Nicholson-Sauls wrote:
> 1) Empty array stands in for empty variadic. [snip]
>
> In reality, though, we have neither of these things. [snip]

Turns out, I was quite wrong, and I'm happy to be.  Empty array is accepted for typesafe variadics just fine ... I'm not sure now why I thought otherwise.

Of course, our tangent is really sort of moot, since the brackets would be required for any pattern with a suffix matching the optional arguments anyhow, at which point there's little point in having the variadic argument.  I reiterate my impression that magical __FILE__ and __LINE__ should be provided by some other means.
September 04, 2012
On 03/09/12 23:48, Chris Nicholson-Sauls wrote:
> On Monday, 3 September 2012 at 11:17:39 UTC, Chris Nicholson-Sauls wrote:
>> 1) Empty array stands in for empty variadic. [snip]
>>
>> In reality, though, we have neither of these things. [snip]
>
> Turns out, I was quite wrong, and I'm happy to be.  Empty array is
> accepted for typesafe variadics just fine ... I'm not sure now why I
> thought otherwise.
>
> Of course, our tangent is really sort of moot, since the brackets would
> be required for any pattern with a suffix matching the optional
> arguments anyhow, at which point there's little point in having the
> variadic argument.  I reiterate my impression that magical __FILE__ and
> __LINE__ should be provided by some other means.

It was a special-case hack to fix a special-case need. It was extremely easy to implement (about 2 hours work) and has been very successful in fixing that need. Everything else that anyone has talked about is at least ten times as complicated, and doesn't seem to offer significant advantages.

It's really easy to come up with over-engineered solutions to these sorts of things.
September 04, 2012
On Tuesday, 4 September 2012 at 09:24:26 UTC, Don Clugston wrote:
> On 03/09/12 23:48, Chris Nicholson-Sauls wrote:
>> I reiterate my impression that magical __FILE__ and
>> __LINE__ should be provided by some other means.
>
> It was a special-case hack to fix a special-case need. It was extremely easy to implement (about 2 hours work) and has been very successful in fixing that need. Everything else that anyone has talked about is at least ten times as complicated, and doesn't seem to offer significant advantages.
>
> It's really easy to come up with over-engineered solutions to these sorts of things.

How difficult would hidden params, triggered by usage, be?  Ie: my function makes use of __CALL_FILE and __CALL_LINE variables by name, therefore they are tacked on  (as const, presumably) and always passed, thanks to diabolic compiler sorcery.  The current solution is fine in a majority of cases, at least so far, but there are going to be moments like what the OP had, and these moments are discouraging especially to newcomers.

I won't pretend to know if it would be easy or not; you're a heck of a lot more familiar with the compiler's code than I am.  But it certainly seems straightforward.
September 04, 2012
On 04/09/12 11:43, Chris Nicholson-Sauls wrote:
> On Tuesday, 4 September 2012 at 09:24:26 UTC, Don Clugston wrote:
>> On 03/09/12 23:48, Chris Nicholson-Sauls wrote:
>>> I reiterate my impression that magical __FILE__ and
>>> __LINE__ should be provided by some other means.
>>
>> It was a special-case hack to fix a special-case need. It was
>> extremely easy to implement (about 2 hours work) and has been very
>> successful in fixing that need. Everything else that anyone has talked
>> about is at least ten times as complicated, and doesn't seem to offer
>> significant advantages.
>>
>> It's really easy to come up with over-engineered solutions to these
>> sorts of things.
>
> How difficult would hidden params, triggered by usage, be?  Ie: my
> function makes use of __CALL_FILE and __CALL_LINE variables by name,
> therefore they are tacked on  (as const, presumably) and always passed,
> thanks to diabolic compiler sorcery.  The current solution is fine in a
> majority of cases, at least so far, but there are going to be moments
> like what the OP had, and these moments are discouraging especially to
> newcomers.

I don't know how that could be done. You need to know the function signature whenever you call the function. If you make the signature dependent on the function body, it cannot work unless you have the source code of the function. The compiler is able to add hidden variables for things like 'this' because it can work out if it is required just by looking at the types involved in the function declaration. But in this case, it can't get it from the signature.

The default argument method we are currently using is a nice trick, because even though default arguments aren't part of the function type, the compiler still sees them in the function signature, so it knows to do a bit of magic.

It's also easy to get nasty forward reference errors when you do that sort of thing.


>
> I won't pretend to know if it would be easy or not; you're a heck of a
> lot more familiar with the compiler's code than I am.  But it certainly
> seems straightforward.


September 05, 2012
On Tuesday, 4 September 2012 at 11:28:23 UTC, Don Clugston wrote:
> I don't know how that could be done. You need to know the function signature whenever you call the function. If you make the signature dependent on the function body, it cannot work unless you have the source code of the function. The compiler is able to add hidden variables for things like 'this' because it can work out if it is required just by looking at the types involved in the function declaration. But in this case, it can't get it from the signature.
>
> The default argument method we are currently using is a nice trick, because even though default arguments aren't part of the function type, the compiler still sees them in the function signature, so it knows to do a bit of magic.
>
> It's also easy to get nasty forward reference errors when you do that sort of thing.
>

Fair enough; I hadn't considered the case of having only the signature to go by.  Maybe an @attribute for it?  ;)  Okay okay, I give.  For now there's making file/line template params, which is fine for something like a custom assertion meant for debug builds, although horrid for release builds.
1 2
Next ›   Last »