August 20, 2007
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
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
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
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
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
1 2
Next ›   Last »