Re: Trouble creating a formatted assert wrapper

2012-09-05 Thread Chris Nicholson-Sauls

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.


Re: Trouble creating a formatted assert wrapper

2012-09-04 Thread Don Clugston

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.


Re: Trouble creating a formatted assert wrapper

2012-09-04 Thread Chris Nicholson-Sauls

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.


Re: Trouble creating a formatted assert wrapper

2012-09-04 Thread Don Clugston

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.





Re: Trouble creating a formatted assert wrapper

2012-09-03 Thread Chris Nicholson-Sauls
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.


Re: Trouble creating a formatted assert wrapper

2012-09-03 Thread Peter Alexander
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?


Re: Trouble creating a formatted assert wrapper

2012-09-03 Thread Chris Nicholson-Sauls
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.




Re: Trouble creating a formatted assert wrapper

2012-09-03 Thread Jonathan M Davis
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


Re: Trouble creating a formatted assert wrapper

2012-09-03 Thread Nick Treleaven

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


Re: Trouble creating a formatted assert wrapper

2012-09-03 Thread Nick Treleaven

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)));

}




Re: Trouble creating a formatted assert wrapper

2012-09-03 Thread Chris Nicholson-Sauls
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.


Trouble creating a formatted assert wrapper

2012-09-02 Thread Peter Alexander
One thing that's always bothered me is that I have to use 
std.string.format to produce useful assert messages:


assert(x == 1, format(x doesn't equal 1, it is %d, x));


Of course, I tried to solve this by producing my own assert-like 
function wrapper:


void myAssert(Args...)(lazy bool condition, lazy Args args)
{
assert(condition, format(args));
}


That's all good, but the problem now is that I get the wrong file 
and line in the assert message, so I tried to use the default arg 
__FILE__ and __LINE__ trick:


void myAssert(Args...)(lazy bool condition, lazy Args args, int 
line = __LINE__, string file = __FILE__)

{
if (!condition)
{
writeln(Assertion failed @ %s:%d, file, line);
writefln(args);
exit(1);
}
}


But I can't have default arguments because of the variadic 
arguments!


Can anyone think of a way around this?


Re: Trouble creating a formatted assert wrapper

2012-09-02 Thread Simen Kjaeraas
On Sun, 02 Sep 2012 19:14:07 +0200, Peter Alexander  
peter.alexander...@gmail.com wrote:


One thing that's always bothered me is that I have to use  
std.string.format to produce useful assert messages:


assert(x == 1, format(x doesn't equal 1, it is %d, x));


Of course, I tried to solve this by producing my own assert-like  
function wrapper:


void myAssert(Args...)(lazy bool condition, lazy Args args)
{
 assert(condition, format(args));
}


That's all good, but the problem now is that I get the wrong file and  
line in the assert message, so I tried to use the default arg __FILE__  
and __LINE__ trick:


void myAssert(Args...)(lazy bool condition, lazy Args args, int line =  
__LINE__, string file = __FILE__)

{
 if (!condition)
 {
 writeln(Assertion failed @ %s:%d, file, line);
 writefln(args);
 exit(1);
 }
}


But I can't have default arguments because of the variadic arguments!

Can anyone think of a way around this?


void myAssert(int line = __LINE__, string file = __FILE__, Args...)(lazy  
bool condition, lazy Args args) {

if (!condition)
{
writefln(Assertion failed @ %s:%d, file, line);
writefln(args);
exit(1);
}
}


--
Simen


Re: Trouble creating a formatted assert wrapper

2012-09-02 Thread Peter Alexander

On Sunday, 2 September 2012 at 18:23:48 UTC, Simen Kjaeraas wrote:
void myAssert(int line = __LINE__, string file = __FILE__, 
Args...)(lazy bool condition, lazy Args args) {

if (!condition)
{
writefln(Assertion failed @ %s:%d, file, line);
writefln(args);
exit(1);
}
}


Nice. I thought of that, but for some reason I thought that you 
couldn't have default args before variadic args.




Re: Trouble creating a formatted assert wrapper

2012-09-02 Thread Simen Kjaeraas
On Sun, 02 Sep 2012 20:46:50 +0200, Peter Alexander  
peter.alexander...@gmail.com wrote:



On Sunday, 2 September 2012 at 18:23:48 UTC, Simen Kjaeraas wrote:
void myAssert(int line = __LINE__, string file = __FILE__,  
Args...)(lazy bool condition, lazy Args args) {

if (!condition)
{
writefln(Assertion failed @ %s:%d, file, line);
writefln(args);
exit(1);
}
}


Nice. I thought of that, but for some reason I thought that you couldn't  
have default args before variadic args.




tbh, I was unsure myself. Sometimes you should just try. :p

--
Simen


Re: Trouble creating a formatted assert wrapper

2012-09-02 Thread timotheecour
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.


There was if I remember some discussion regarding not passing 
__LINE__,__FILE__ in assert related functions because of that.


If backtrace worked properly we should be able to go up the stack 
and get line number information when the assert fails (no time 
penalty when assert doesn't fail).


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.


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).


Would that be possible to add?





Re: Trouble creating a formatted assert wrapper

2012-09-02 Thread Philippe Sigaud
On Sun, Sep 2, 2012 at 8:46 PM, Peter Alexander
peter.alexander...@gmail.com wrote:
 On Sunday, 2 September 2012 at 18:23:48 UTC, Simen Kjaeraas wrote:

 void myAssert(int line = __LINE__, string file = __FILE__, Args...)(lazy
 bool condition, lazy Args args) {
 if (!condition)
 {
 writefln(Assertion failed @ %s:%d, file, line);
 writefln(args);
 exit(1);
 }
 }


 Nice. I thought of that, but for some reason I thought that you couldn't
 have default args before variadic args.


IIRC, you can even have them before standard template args. Template
arguments are much more versatile (or hard-working) than function
arguments.


Re: Trouble creating a formatted assert wrapper

2012-09-02 Thread Peter Alexander

On Sunday, 2 September 2012 at 19:31:24 UTC, 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.


You can easily counter that by delegating the body to a 
non-template function.


Even then, it's only in non-release builds and it's a small 
function anyway.




Re: Trouble creating a formatted assert wrapper

2012-09-02 Thread Timon Gehr

On 09/02/2012 07:14 PM, Peter Alexander wrote:

One thing that's always bothered me is that I have to use
std.string.format to produce useful assert messages:

assert(x == 1, format(x doesn't equal 1, it is %d, x));


Of course, I tried to solve this by producing my own assert-like
function wrapper:

void myAssert(Args...)(lazy bool condition, lazy Args args)
{
 assert(condition, format(args));
}


That's all good, but the problem now is that I get the wrong file and
line in the assert message, so I tried to use the default arg __FILE__
and __LINE__ trick:

void myAssert(Args...)(lazy bool condition, lazy Args args, int line =
__LINE__, string file = __FILE__)
{
 if (!condition)
 {
 writeln(Assertion failed @ %s:%d, file, line);
 writefln(args);
 exit(1);
 }
}


But I can't have default arguments because of the variadic arguments!

Can anyone think of a way around this?


I don't think there is a deep reason why IFTI shouldn't succeed in this 
case.


Re: Trouble creating a formatted assert wrapper

2012-09-02 Thread Peter Alexander

On Sunday, 2 September 2012 at 20:30:26 UTC, Timon Gehr wrote:

On 09/02/2012 07:14 PM, Peter Alexander wrote:

One thing that's always bothered me is that I have to use
std.string.format to produce useful assert messages:

assert(x == 1, format(x doesn't equal 1, it is %d, x));


Of course, I tried to solve this by producing my own 
assert-like

function wrapper:

void myAssert(Args...)(lazy bool condition, lazy Args args)
{
assert(condition, format(args));
}


That's all good, but the problem now is that I get the wrong 
file and
line in the assert message, so I tried to use the default arg 
__FILE__

and __LINE__ trick:

void myAssert(Args...)(lazy bool condition, lazy Args args, 
int line =

__LINE__, string file = __FILE__)
{
if (!condition)
{
writeln(Assertion failed @ %s:%d, file, line);
writefln(args);
exit(1);
}
}


But I can't have default arguments because of the variadic 
arguments!


Can anyone think of a way around this?


I don't think there is a deep reason why IFTI shouldn't succeed 
in this case.


Consider:

myAssert(false, %d, 1);

What is Args? %d, 1 could refer to the optional arguments, or 
the variadic arguments. Both match.