August 20, 2007 Re: better assertions and __FILE__ (compile time functions) | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Bruce Adams | Bruce Adams wrote: ... > I can see from using a variant of your example that is possible now. > I forgot we had CTFE. I was surprised it allows arbitrary strings to be compiled as I though mxins were supposed to use code segments that have been parsed already. > Anyway, I'm still struggling a bit with it. My main problem can be boiled > down to the following example. > > char[] int2str(int foo_) > { > return std.metastrings.ToString!(foo_); > } This is almost correct, see below. > char[] int2str(int foo_) > { > return std.metastrings.ToString(foo_); > } std.metastrings.ToString is a template, which must be instanciated with !, so this is not correct. My example was bad, I'm sorry, it didn't break because I only used these __LINE__ and __FILE__ tokens. At the very bottom of http://www.digitalmars.com/d/function.html the reason is explained: "Any functions that execute at compile time must also be executable at run time. The compile time evaluation of a function does the equivalent of running the function at run time. " For int2str, this is not the case. If you only need compile time execution, you can rewrite these functions as templates. For my original example: template assertEqual(char[] actual, char[] expected) { const char[] assertEqual = `if (` ~ actual ~ `!=` ~ expected ~ `) { ` `writefln("Equality assertion failed in " ~ __FILE__ ~ " at line " ~ std.metastrings.ToString!(__LINE__));` `writefln("expected value: '", ` ~ expected ~ `, "'");` `writefln("actual value: '", ` ~ actual ~ `, "'");` `assert(false);}`; } mixin(assertEqual!("foo","bar")); > Incidentally is there a way of specifying you only want a function to be evaluated at compile time? Perhaps the static keyword? > My plan when this kind of thing comes up is to have one function for > the run-time portion and a seperate code generator for the compile time stuff. See the eval template also at http://www.digitalmars.com/d/function.html To determine whether a parameter is a constant or not (for dispatching), perhaps one could use is-expressions to try to take the adress: is( typeof(&arg)). That should evaluate to false for constants (at compile time), but true for run-time parameters. Haven't tested it though. | |||
August 21, 2007 Re: better assertions and __FILE__ (compile time functions) | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Lutger |
Right, thanks. I'm nearly there. Here's where I'm at:
// for example only
void assertWrapper(char[] file_, uint line_) {
_d_assert(file_,line_);
}
// the run-time assert part
void assertEqual(Type)(Type actual_, Type expected_,
char[] file_,
uint line_) {
if (actual_ != expected_) {
writefln("Equality assertion failed");
writefln("actual: '", actual_, "'");
writefln("expected: '", expected_, "'");
}
assertWrapper(file_,line_);
}
const char[] assertEqual4(const char[] actualVar_, const char[] expectedVar_) {
return "assertEqual!(int)("[]
~actualVar_
~","[]
~expectedVar_
~",cast(char[])(__FILE__),__LINE__);"[];
}
const char[] assertEqual5(T)(const char[] actualVar_, const char[] expectedVar_) {
return "assertEqual!("
~typeof(T).stringof
~")("[]
~actualVar_
~","[]
~expectedVar_
~",cast(char[])(__FILE__),__LINE__);"[];
}
unittest {
// declare at run-time
const int var3 = 1;
const int var4 = 2;
int var5 = 1;
int var6 = 2;
// okay - but must give name of variables
writefln(assertEqual4("var5"[],"var6"[]));
mixin(assertEqual4("var5"[],"var6"[]));
// must provide name and type
mixin(assertEqual5!(int)("var5"[],"var6"[]));
// must provide name and type
mixin(assertEqual5!(typeof(var5))(var5.stringof,var6.stringof));
}
I reckon "mixin(assertEqual(var5,var6));" should be possible but I haven't quite figured it out yet.
Regards,
Bruce.
Lutger Wrote:
[Some helpful stuff]
| |||
August 21, 2007 Re: better assertions and __FILE__ (compile time functions) | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Bruce Adams | Hi all,
Still stuck. How do I get the template to include the name of a run-time variable at compile-time? Please somebody put me out of my misery.
template assertEqual8(actual_, expected_)
{
const char[] assertEqual8(actual_ a_, expected_ e_) {
return
"mixin(assertEqual5!("[]
~actual_.stringof
~")("[]
~a_.stringof
~","[]
~e_.stringof
~"));"[];
}
}
alias assertEqual8!(int, int) assertEqual9;
unittest {
// all fine
// writes: "mixin(assertEqual5!(int)(a_,e_));" when var5, var6 wanted
writefln(assertEqual9(var5,var6));
// not allowed at CT :(
mixin(assertEqual9(var5,var6))
}
UnitTest.d(246): Error: variable var5 is used before initialization
UnitTest.d(246): Error: cannot evaluate assertEqual8(var5,var6) at compile time
UnitTest.d(246): Error: argument to mixin must be a string, not (assertEqual8(va
r5,var6))
Bruce Adams Wrote:
>
> Right, thanks. I'm nearly there. Here's where I'm at:
>
> // for example only
> void assertWrapper(char[] file_, uint line_) {
> _d_assert(file_,line_);
> }
>
> // the run-time assert part
> void assertEqual(Type)(Type actual_, Type expected_,
> char[] file_,
> uint line_) {
> if (actual_ != expected_) {
> writefln("Equality assertion failed");
> writefln("actual: '", actual_, "'");
> writefln("expected: '", expected_, "'");
> }
> assertWrapper(file_,line_);
> }
>
> const char[] assertEqual4(const char[] actualVar_, const char[] expectedVar_) {
> return "assertEqual!(int)("[]
> ~actualVar_
> ~","[]
> ~expectedVar_
> ~",cast(char[])(__FILE__),__LINE__);"[];
> }
>
> const char[] assertEqual5(T)(const char[] actualVar_, const char[] expectedVar_) {
> return "assertEqual!("
> ~typeof(T).stringof
> ~")("[]
> ~actualVar_
> ~","[]
> ~expectedVar_
> ~",cast(char[])(__FILE__),__LINE__);"[];
> }
>
> unittest {
> // declare at run-time
> const int var3 = 1;
> const int var4 = 2;
>
> int var5 = 1;
> int var6 = 2;
>
> // okay - but must give name of variables
> writefln(assertEqual4("var5"[],"var6"[]));
> mixin(assertEqual4("var5"[],"var6"[]));
>
> // must provide name and type
> mixin(assertEqual5!(int)("var5"[],"var6"[]));
>
> // must provide name and type
> mixin(assertEqual5!(typeof(var5))(var5.stringof,var6.stringof));
> }
>
> I reckon "mixin(assertEqual(var5,var6));" should be possible but I haven't quite figured it out yet.
>
> Regards,
>
> Bruce.
>
>
> Lutger Wrote:
>
> [Some helpful stuff]
>
| |||
August 22, 2007 Re: better assertions and __FILE__ (compile time functions) | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Bruce Adams | Bruce Adams wrote:
> Hi all,
> Still stuck. How do I get the template to include the name of a run-time variable at compile-time? Please somebody put me out of my misery.
>
> template assertEqual8(actual_, expected_)
> {
> const char[] assertEqual8(actual_ a_, expected_ e_) { return "mixin(assertEqual5!("[]
> ~actual_.stringof
> ~")("[]
> ~a_.stringof
> ~","[]
> ~e_.stringof
> ~"));"[];
> }
> }
> alias assertEqual8!(int, int) assertEqual9;
>
> unittest {
> // all fine
> // writes: "mixin(assertEqual5!(int)(a_,e_));" when var5, var6 wanted
> writefln(assertEqual9(var5,var6));
>
> // not allowed at CT :(
> mixin(assertEqual9(var5,var6))
> }
>
> UnitTest.d(246): Error: variable var5 is used before initialization
> UnitTest.d(246): Error: cannot evaluate assertEqual8(var5,var6) at compile time
> UnitTest.d(246): Error: argument to mixin must be a string, not (assertEqual8(va
> r5,var6))
>
>
> Bruce Adams Wrote:
>
>> Right, thanks. I'm nearly there. Here's where I'm at:
>>
>> // for example only
>> void assertWrapper(char[] file_, uint line_) {
>> _d_assert(file_,line_);
>> }
>> // the run-time assert part
>> void assertEqual(Type)(Type actual_, Type expected_, char[] file_, uint line_) {
>> if (actual_ != expected_) {
>> writefln("Equality assertion failed");
>> writefln("actual: '", actual_, "'");
>> writefln("expected: '", expected_, "'");
>> }
>> assertWrapper(file_,line_);
>> }
>>
>> const char[] assertEqual4(const char[] actualVar_, const char[] expectedVar_) {
>> return "assertEqual!(int)("[]
>> ~actualVar_
>> ~","[]
>> ~expectedVar_
>> ~",cast(char[])(__FILE__),__LINE__);"[]; }
>>
>> const char[] assertEqual5(T)(const char[] actualVar_, const char[] expectedVar_) {
>> return "assertEqual!(" ~typeof(T).stringof
>> ~")("[]
>> ~actualVar_
>> ~","[]
>> ~expectedVar_
>> ~",cast(char[])(__FILE__),__LINE__);"[]; }
>>
>> unittest {
>> // declare at run-time
>> const int var3 = 1;
>> const int var4 = 2;
>>
>> int var5 = 1;
>> int var6 = 2;
>>
>> // okay - but must give name of variables
>> writefln(assertEqual4("var5"[],"var6"[]));
>> mixin(assertEqual4("var5"[],"var6"[]));
>>
>> // must provide name and type
>> mixin(assertEqual5!(int)("var5"[],"var6"[]));
>>
>> // must provide name and type
>> mixin(assertEqual5!(typeof(var5))(var5.stringof,var6.stringof));
>> }
>>
>> I reckon "mixin(assertEqual(var5,var6));" should be possible but I haven't quite figured it out yet.
>>
>> Regards,
>>
>> Bruce.
>>
>>
>> Lutger Wrote:
>>
>> [Some helpful stuff]
>>
>
Try this...
void assertEqual (T) (T actual, T expected, char[] file, uint line) {
if (actual != expected) {
writeln("Equality assertion failed.");
writefln(" actual: '%s'", actual);
writefln(" expected: '%s'", expected);
_d_assert(file, line);
}
}
template MAssertEqual (alias actual, alias expected) {
const MAssertEqual =
`assertEqual(`
~actual.stringof~
`, `
~expected.stringof~
`, __FILE__, __LINE__);`
;
}
unittest {
int var5 = 1;
int var6 = 2;
mixin(MAssertEqual!(var5, var6)); // -> assertEqual(var5, var6, __FILE__, __LINE__);
}
Note: Untested.
-- Chris Nicholson-Sauls
| |||
August 25, 2007 Re: better assertions and __FILE__ (compile time functions) | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Chris Nicholson-Sauls | Chris Nicholson-Sauls Wrote:
>
> Try this...
>
> void assertEqual (T) (T actual, T expected, char[] file, uint line) {
> if (actual != expected) {
> writeln("Equality assertion failed.");
> writefln(" actual: '%s'", actual);
> writefln(" expected: '%s'", expected);
> _d_assert(file, line);
> }
> }
>
> template MAssertEqual (alias actual, alias expected) {
> const MAssertEqual =
> `assertEqual(`
> ~actual.stringof~
> `, `
> ~expected.stringof~
> `, __FILE__, __LINE__);`
> ;
> }
>
> unittest {
> int var5 = 1;
> int var6 = 2;
>
> mixin(MAssertEqual!(var5, var6)); // -> assertEqual(var5, var6, __FILE__, __LINE__);
> }
>
> Note: Untested.
>
> -- Chris Nicholson-Sauls
That doesn't work, but this does:
template MAssertEqual (alias actual, alias expected) {
const AssertEqual =
`assertEqual!(` ~typeof(actual).stringof ~`)(`
~actual.stringof~
`, `
~expected.stringof~
`, cast(char[])(__FILE__), __LINE__);`
;
}
So problem solved. I'm not sure why template type deduction isn't working here (a D2.0 issue?), but thanks anyway. I can now run away and write Dunit if someone hasn't already done it. Of course, if they had and I knew about it I probably wouldn't have started this thread. Thanks, I've learned a bit more useful template meta foo.
Regards,
Bruce
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply