Jump to page: 1 2
Thread overview
better assertions and __FILE__
Aug 15, 2007
Bruce Adams
Aug 16, 2007
Bruce Adams
Re: better assertions and __FILE__ (call stack reflection)
Aug 17, 2007
Bruce Adams
Aug 17, 2007
Lutger
Aug 17, 2007
Lutger
Re: better assertions and __FILE__ (compile time functions)
Aug 20, 2007
Bruce Adams
Aug 20, 2007
Lutger
Aug 21, 2007
Bruce Adams
Aug 21, 2007
Bruce Adams
Aug 25, 2007
Bruce Adams
Re: better assertions and __FILE__ (char[] vs. string)
Aug 16, 2007
Bruce Adams
Aug 16, 2007
Frank Benoit
Aug 17, 2007
Bruce Adams
Aug 17, 2007
Deewiant
August 15, 2007
Hi,
    Another FAQ item I couldn't find. I'm looking to implement some wrappers around assert as assert is too primative and doesn't give me enough information. I want to go down the xUnit path E.g.

in the code:
   assertEqual(foo,bar);

leading to output:
   Equality assertion failed in file.cpp at line 10
   Expected Value: 10
   Actual Value: 5

I got as far as:

void assertEqual(Type)(Type actual_,
                                Type expected_,
		            char[] file_,
		            uint line_) {
   if (actual_ != expected_) {
      writefln("Equality assertion failed");
      writefln("actual:   '", actual_, "'");
      writefln("expected: '", expected_, "'");
      _d_assert(file_,line_);
   }
}

This lets me use:

   assertEqual!(string)("foo","bar",cast(char[])(__FILE__),__LINE__);

Where I'm having trouble is getting __FILE__ and __LINE__ added (presumably using a mixin) so I can avoid the cruft.

As a side issue how do I get string constants implicitly converted to
char[] or better yet string.
In my example above

   assertEqual("foo","bar",cast(char[])(__FILE__),__LINE__);

also works but only because "foo".length == "bar".length

   // broken!
   assertEqual("foo","bar2",cast(char[])(__FILE__),__LINE__);

Final question to prove I'm a noob. In std.asserterror shouldn't

 _d_assert(char[] file_,uint line_);

actually be:

 _d_assert(string file_,uint line_);

Regards,

Bruce.

August 16, 2007
Bruce Adams Wrote:

> 
> Hi,
>     Another FAQ item I couldn't find. I'm looking to implement some wrappers around assert as assert is too primative and doesn't give me enough information. I want to go down the xUnit path E.g.
> 
> in the code:
>    assertEqual(foo,bar);
> 
> leading to output:
>    Equality assertion failed in file.cpp at line 10
>    Expected Value: 10
>    Actual Value: 5
> 
> I got as far as:
> 
> void assertEqual(Type)(Type actual_,
>                                 Type expected_,
> 		            char[] file_,
> 		            uint line_) {
>    if (actual_ != expected_) {
>       writefln("Equality assertion failed");
>       writefln("actual:   '", actual_, "'");
>       writefln("expected: '", expected_, "'");
>       _d_assert(file_,line_);
>    }
> }
> 
> This lets me use:
> 
>    assertEqual!(string)("foo","bar",cast(char[])(__FILE__),__LINE__);
> 
> Where I'm having trouble is getting __FILE__ and __LINE__ added (presumably using a mixin) so I can avoid the cruft.
> 

Here are a few more things I've learned on my travels around the various D web-pages.

__FILE__ & __LINE__ are expanded by the tokeniser not the parser. This implies that they would not be available for use in mixins as they will already have been expanded. This is confirmed with a quick test. So what I'm trying to do is not currently possible.

I have seen two proposals for improvements to D bandied around.

1) "context" functions

// does not exist
void context(__line, __file) assertEqual(int a, int b) {
   if (a != b) {
     writefln("equality assertion failed");
     writefln("expected: ",a);
     writefln("actual: ",b);
     _d_assert(__line,__file);
   }
}

2) Access to the call stack through "trace" something like:

import std.trace;  // does not exist yet

void assertEqual(int a, int b) {
   if (a != b) {
     writefln("equality assertion failed");
     writefln("expected: ",a);
     writefln("actual: ",b);
     StackFrame callerFrame = getStack().up();
     uint callingLine = callerFrame.getLine();
     char[] callingFile = callerFrame.getFile();
     _d_assert(callingLine, callingFile);
   }
}

I think the latter has more appeal and more support. You can use it for generating stack traces and core dumps for example. However, I have no idea of what status these ideas are at. There's nothing in the issue tracking system. I'm not sure if that's the right place for frivolous feature requests. Has anyone heard anything on the grapevine?
Are there language development roadmap and feature request pages knocking around the web somewhere that I've yet to find?

Regards,

Bruce.




August 16, 2007
Okay. So having realised my first idea is not possible with current D (prove me wrong please!). What about the char array versus string
malarcky. Can anyone help with that?

How do I get "foo" to be implicitly interpreted as char[] rather than char[3]. I though the WYSIWYG thing might do it i.e. r"foo" but it doesn't. In fact I'm not sure what it does do.

Bruce Adams Wrote:

> 
> Hi,
>     Another FAQ item I couldn't find. I'm looking to implement some wrappers around assert as assert is too primative and doesn't give me enough information. I want to go down the xUnit path E.g.
> 
> in the code:
>    assertEqual(foo,bar);
> 
> leading to output:
>    Equality assertion failed in file.cpp at line 10
>    Expected Value: 10
>    Actual Value: 5
> 
> I got as far as:
> 
> void assertEqual(Type)(Type actual_,
>                                 Type expected_,
> 		            char[] file_,
> 		            uint line_) {
>    if (actual_ != expected_) {
>       writefln("Equality assertion failed");
>       writefln("actual:   '", actual_, "'");
>       writefln("expected: '", expected_, "'");
>       _d_assert(file_,line_);
>    }
> }
> 
> This lets me use:
> 
>    assertEqual!(string)("foo","bar",cast(char[])(__FILE__),__LINE__);
> 
> Where I'm having trouble is getting __FILE__ and __LINE__ added (presumably using a mixin) so I can avoid the cruft.
> 
> As a side issue how do I get string constants implicitly converted to
> char[] or better yet string.
> In my example above
> 
>    assertEqual("foo","bar",cast(char[])(__FILE__),__LINE__);
> 
> also works but only because "foo".length == "bar".length
> 
>    // broken!
>    assertEqual("foo","bar2",cast(char[])(__FILE__),__LINE__);
> 
> Final question to prove I'm a noob. In std.asserterror shouldn't
> 
>  _d_assert(char[] file_,uint line_);
> 
> actually be:
> 
>  _d_assert(string file_,uint line_);
> 
> Regards,
> 
> Bruce.
> 

August 16, 2007
Bruce Adams schrieb:
> How do I get "foo" to be implicitly interpreted as char[] rather than char[3].

"foo"[]
August 17, 2007
Frank Benoit Wrote:

> Bruce Adams schrieb:
> > How do I get "foo" to be implicitly interpreted as char[] rather than char[3].
> 
> "foo"[]

Thanks. Where is that piece of syntactic sugar documented?

There's still a problem though. The following line:

assertEqual("foo"[],"bar2"[],cast(char[])(__FILE__),__LINE__);

fails to compile with:

UnitTest.d(49): template UnitTest.assertEqual(Type) cannot deduce template fun
ion from argument types (invariant(char)[],invariant(char)[],char[],long)

but the explicit instantiation below works.

assertEqual!(invariant(char[]))("foo"[],"bar2"[],cast(char[])(__FILE__),__LINE__);

What's going on?

Regards,

Bruce.

August 17, 2007
I have given in and raised this as an issue:

http://d.puremagic.com/issues/show_bug.cgi?id=1425

duplicated below for discussion purposes:

For improved support for assertions, logging code and stack traces it would be
useful to have means of identifying the calling frame of reference. This would
also have the advantage of rendering __LINE__ and its ilk redundant.
For example it is not currently possible to implement a cppunit like
assertEqual function.
The best I can achieve is:

void assertEqual(Type)(Type actual_, Type expected_,
                       char[] file_,
                       uint line_) {
   if (actual_ != expected_) {
      writefln("Equality assertion failed");
      writefln("actual:   '", actual_, "'");
      writefln("expected: '", expected_, "'");
   }
   _d_assert(file_,line_);
}

Which has to be used as:

assertEqual!(string)("foo","bar",cast(char[])(__FILE__),__LINE__);

It should be possible to achieve a more natural syntax like:

assertEqual("foo","bar");

Several proposals seem have been made on the newsgroups but none has been
raised as a request here.
I personally think the best approach is to have a library function

stackFrame[] callStack = std.trace();

By default the calling frame would be something like:

class stackFrame {
   stackFrame* parent;
   object[]    arguments;
}

When functions request source identification the compiler would have to
include mapping information so its not a pure library issue.
E.g

class SourceStackFrame: public StackFrame {
// inherited
//   stackFrame* parent;
//   object[]    arguments;
   uint        parentLine;
   string*     parentFile;
   string*     parentFunction;
}

I imagine two ways of creating such a structure.
Use of an analogue to __FILE__ e.g. the so called "context" keyword
would tell the compiler to use the special stack frame for a specific call
only.
A command line switch could tell the compiler to always use the source stack
frame format - with resulting code bloat.
August 17, 2007
Bruce Adams wrote:
> Frank Benoit Wrote:
>> Bruce Adams schrieb:
>>> How do I get "foo" to be implicitly interpreted as char[] rather than char[3].
>> "foo"[]
> 
> Thanks. Where is that piece of syntactic sugar documented?
> 

http://www.digitalmars.com/d/arrays.html

"The [] is shorthand for a slice of the entire array."

-- 
Remove ".doesnotlike.spam" from the mail address.
August 17, 2007
Bruce Adams wrote:
> 
> Here are a few more things I've learned on my travels around the various D web-pages.
> 
> __FILE__ & __LINE__ are expanded by the tokeniser not the parser. This implies that they would not be available for use in mixins as they will already have been expanded. This is confirmed with a quick test. So what I'm trying to do is not currently possible.
>

It's possible to use CTFE with string mixins to achieve this. I have whipped up something quick, ugly as hell but could be improved using std.metastrings.Format:


char[] assertEqual(char[] actual, char[] expected)
{
    return  `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);}`;
}

used as:

mixin(assertEqual("foo","bar"));


If you can live with a) having to use 'mixin', b) ugliness of compile time string manipulation and perhaps c) sometimes hard to follow error messages, you can do most of anything you want with CTFE and string mixins.
I think if one would make work of this most of the tediousness could be solved with some boilerplate code.

August 17, 2007
Also note that it is necessary to 'public import std.metastrings' if this code is used across modules, due to the mixin thing.
August 20, 2007
Lutger Wrote:

> Bruce Adams wrote:
> > 
> > Here are a few more things I've learned on my travels around the various D web-pages.
> > 
> > __FILE__ & __LINE__ are expanded by the tokeniser not the parser. This implies that they would not be available for use in mixins as they will already have been expanded. This is confirmed with a quick test. So what I'm trying to do is not currently possible.
> >
> 
> It's possible to use CTFE with string mixins to achieve this. I have whipped up something quick, ugly as hell but could be improved using std.metastrings.Format:
> 
> 
> char[] assertEqual(char[] actual, char[] expected)
> {
>      return  `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);}`;
> }
> 
> used as:
> 
> mixin(assertEqual("foo","bar"));
> 
> 
> If you can live with a) having to use 'mixin', b) ugliness of compile
> time string manipulation and perhaps c) sometimes hard to follow error
> messages, you can do most of anything you want with CTFE and string mixins.
> I think if one would make work of this most of the tediousness could be
> solved with some boilerplate code.
> 

I'd rather live with A) - than without the option to do this at all.
B) is better than it was in C++. I'm already struggling with C) using DMD, if you'll pardon the pun.

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

Fails to compile with

c:\dmd\bin\..\src\phobos\std\metastrings.d(102): Error: expression cast(long)foo
_ is not a valid template value argument
c:\dmd\bin\..\src\phobos\std\metastrings.d(85): Error: expression cast(long)foo_
 < 0L is not constant or does not evaluate to a bool

Without the shriek it also fails:

char[] int2str(int foo_)
{
   return std.metastrings.ToString(foo_);
}

dmd.exe -c UnitTest.d -ofUnitTest.do -cov
c:\dmd\bin\..\src\phobos\std\metastrings.d(74): template std.metastrings.ToStrin
g(ulong U) is not a function template
UnitTest.d(124): template std.metastrings.ToString(ulong U) cannot deduce templa
te function from argument types (int)
UnitTest.d(124): Error: cannot implicitly convert expression ((ToString(ulong U)
)(foo_)) of type int to char[]

Its not obvious to me what I'm doing wrong.

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.

Regards,

Bruce.
« First   ‹ Prev
1 2