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