June 01, 2006
pragma schrieb am 2006-06-01:
> To sum up: I honestly feel that the two capabilities, assert() and writefln(),
> should be merged into an extended assert() statment, for the sake of encouraging
> better coding and library use.

That's easy:

# import std.stdio;
# import std.stdarg;
#
# bool assertln(...){
#   writefx(stdout, _arguments, _argptr, 1);
#   return false;
# }
#

#
#   // ...
#   assert(a == b || assertln("%s != %s", a, b));
#   // ...
#

Thomas


June 02, 2006
kris wrote:
> Oskar Linde wrote:
> 
>> pragma wrote:
>>
>>> Anyway, so I run some code that trips on an assert, and it coughs up
>>> "foobar.d(42)" as where I need to look.  The assert has done its job, as I go to
>>> line #42 and go hunting for the reason behind why it tripped up.  As I'm
>>> basically flying blind (no watch window and no stack trace), my next step is
>>> almost always: add a writefln() before the assert to get some more information
>>> as to how this happened.  Meshing those two steps seems like an obvious choice
>>> to me.
>>
>>
>>
>> What I do is redefine the implementation of assert to do:
>>
>>  *(cast(int *)0) = 0;
>>
>> That way, I get a segmentation fault and a core dump that the debugger (gdb) is able to use to present me with a back trace and (all) local variables available for inspection. This is immensely more useful than letting assert throw an exception, which means losing all state and stack trace information.
>>
>> /Oskar
> 
> 
> 
> And therein lies the key: what everyone is asking for is a means to capture additional state with the assert()
> 
> Ideally, all code-testing would be performed within the comforting arms of a debugger. But it doesn't happen that way and, due to Murphy's law, the one and only time your code trips up is when it's not in the debugger. That's when you need additional state to help track things down; especially with those "non repeatable" bugs.
> 
> Having said that, a very large part of the valuable state is the stack-trace ~ "how did we get here" can be just as important as some key variable. Often more so. Thus, I tend to look at assert as the bare minimum of tools; scraping the barrel, if you will. That goes to show how poor the runtime diagnostic support really is in D at this time ~ we're actually better off with printf() than most anythng else :)
> 
> Thus when all is said and done, having support for a stack-trace seems far more valuable than the 'convenience' of an assert message. Although in the absence of the former, it's easy to see why assert() gets so much attention.
> 
> Finally, I suspect adding printf formatting to assert() would be binding complexity at a delicate level; partly because the formatting might try to allocate memory?
> 
> Let's get stack-tracing supported, instead of depending upon the marginally useful assert() statement :D
> 
> - Kris

I'm sorry but I really have to insert my skepticism here about stack traces.

Upon first glance it sounds like a wonderful idea, until you get to where Java is at.  Literally hundreds of lines of stack traces dumped into log files to wade thru, most of them completely useless because: THEY DON'T CONTAIN STATE!!!

Sure they have the call-stack state so you can see where the function calls came from but there are no local variables, no function parameter values, no class/struct dumps; basically nothing useful for anything more complex than the simplest case of a deterministic function call, and even then it's not too terribly useful.

While I agree that it is better than nothing, we can still do better. An entire run-time debugging framework is what we really want to shoot for.  Exception logging, tracing, dumping of object contents, reading local variables, reading function parameters, etc.  This probably requires the help of a compile-time reflection system (where certain properties of objects are translated by the compiler into literal expressions).  Run-time reflection isn't really necessary.

-- 
Regards,
James Dunne
June 02, 2006
On Thu, 1 Jun 2006, James Dunne wrote:

> I'm sorry but I really have to insert my skepticism here about stack traces.
> 
> Upon first glance it sounds like a wonderful idea, until you get to where Java is at.  Literally hundreds of lines of stack traces dumped into log files to wade thru, most of them completely useless because: THEY DON'T CONTAIN STATE!!!
> 
> Sure they have the call-stack state so you can see where the function calls came from but there are no local variables, no function parameter values, no class/struct dumps; basically nothing useful for anything more complex than the simplest case of a deterministic function call, and even then it's not too terribly useful.
> 
> While I agree that it is better than nothing, we can still do better. An entire run-time debugging framework is what we really want to shoot for. Exception logging, tracing, dumping of object contents, reading local variables, reading function parameters, etc.  This probably requires the help of a compile-time reflection system (where certain properties of objects are translated by the compiler into literal expressions).  Run-time reflection isn't really necessary.
> 
> -- 
> Regards,
> James Dunne

At that point, you really just want the core file.  Given the program image and the core, you can do all of the above.
June 02, 2006
James Dunne wrote:
> I'm sorry but I really have to insert my skepticism here about stack traces.
> 
> Upon first glance it sounds like a wonderful idea, until you get to where Java is at.  Literally hundreds of lines of stack traces dumped into log files to wade thru, most of them completely useless because: THEY DON'T CONTAIN STATE!!!
> 
> Sure they have the call-stack state so you can see where the function calls came from but there are no local variables, no function parameter values, no class/struct dumps; basically nothing useful for anything more complex than the simplest case of a deterministic function call, and even then it's not too terribly useful.
> 
> While I agree that it is better than nothing, we can still do better. An entire run-time debugging framework is what we really want to shoot for.  Exception logging, tracing, dumping of object contents, reading local variables, reading function parameters, etc.  This probably requires the help of a compile-time reflection system (where certain properties of objects are translated by the compiler into literal expressions).  Run-time reflection isn't really necessary.


Fair enough;

I find it vaguely interesting that there's been a log4j clone publicly available for 25 months now, yet I'm perhaps the only one who uses it -- lol -- what does that tell you? If anything?

:-D
June 02, 2006
Sean Kelly wrote:
> pragma wrote:
>>
>> Another way to look at it is in the use of static assert().  With the
>> compile-time regexp processor(s) out there, they halt on static assert() and
>> then cough up some rudimentary explaination as to *why* using pragma(msg).  I
>> wouldn't even consider either implementation usable without the msg/assert
>> idiom, so I don't really use them apart from each other.  In fact, I'll argue
>> that its impossible to meaningfully extend the compiler/D-grammar through
>> templates without using the two together; the library user just wouldn't have a
>> clue otherwise.

[ie, just like C++!]
That's my experience too. It's possible to have excellent usability now that we have sudden-death static asserts.


> Good point.  If this change were made, would it apply to static assert as well?  It would certainly be nice.

The case for a message in static assert is very much stronger than for assert.
(a) You don't have a debugger -- there's no way of finding what's going on apart from seeing the assert.
(b) The message is always for the programmer, not the end user.
(c) Established practice is to use pragma(msg) with static assert(0).

My code is littered with:

static if (!cond) {
  pragma(msg, "xxx");
  static assert(0);
}

It would be so much cleaner to replace this with
static assert(cond, "xxx");
(and it would accentuate the superiority of D templates over C++).
June 02, 2006
Daniel Keep wrote:
> 
> Bruno Medeiros wrote:
>> Daniel Keep wrote:
>>> BCS wrote:
>>>> In article <e5im92$hlo$2@digitaldaemon.com>, akcom says...
>>>> [...]
>>>>> Just my thoughts, I think it's definitely got some merits, although
>>>>> one must consider that the assert( statementToTest ) would give you
>>>>> the line that threw the assert, which makes a message a bit less
>>>>> important. 
>>>> if the message is non static then a lot of info can be printed.
>>>>
>>>> assert(str.length < 5, `the string "` ~ str ~ `" is more than 5 char
>>>> long");
>>>>
>>>> I'll vote for this.
>>>>
>>> I like the idea, but here's a better one that I could have used when
>>> testing my MMX routines:
>>>
>>> # ubyte[] a = new ubyte[4096]; // src1
>>> # ubyte[] b = new ubyte[4096]; // src2
>>> # ubyte[] c = new ubyte[4096]; // dst
>>> # ubyte[] d = new ubyte[4096]; // result calculated "long hand"
>>> #
>>> # // ...
>>> #
>>> # adds(a, b, c);
>>> # assert(c == d);
>>>
>>> Working out *why* it's asserted is no fun whatsoever.  YES it's told you
>>> there's a bug, but in this case, it hasn't even told you what that bug
>>> is.  Just that it exists.
>>>
>>> In this case, using a message would help; I could tell myself where the
>>> assert had failed.  Even better would be a few more asserts:
>>>
>>> # assertArrayEqual(c, d);
>>>
>>> Which might print:
>>>
>>> AssertError foo.d line 2001: mismatch at element 42: expected "6", got
>>> "9".
>>>
>>> I would have KILLED for that a few weeks ago :)  I'd implement that
>>> myself, except that `assert` seems to be the ONLY statement in D that
>>> automatically passes the source file and line number to the exception.
>>>
>>> Walter: is there any technical reason why we can't get Exceptions to
>>> automatically have source file and line number assigned when
>>> instantiated?
>>>
>> You mean when thrown, no?
>>
>>> Hmm.  Seem to have gone off topic somewhat.  Gomen.
>>>
>>>     -- Daniel
>>>
>>
> 
> # try
> # {
> #     // ...
> # }
> # catch( Exception e )
> # {
> #     // Hmm... nevermind
> #     throw e;
> # }
> 
> See the problem? :P
> 

Easily solvable I think. 'throw' will only fill file-line info once for a given exception (that is, it fills only if the exception hasn't that info already).
But now that you mention that idiom, I wonder how other languages deal with that. I'll have to check it out

-- 
Bruno Medeiros - CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
June 02, 2006
James Dunne wrote:
> kris wrote:
>> Oskar Linde wrote:
>>
>>> pragma wrote:
>>>
>>>> Anyway, so I run some code that trips on an assert, and it coughs up
>>>> "foobar.d(42)" as where I need to look.  The assert has done its job, as I go to
>>>> line #42 and go hunting for the reason behind why it tripped up.  As I'm
>>>> basically flying blind (no watch window and no stack trace), my next step is
>>>> almost always: add a writefln() before the assert to get some more information
>>>> as to how this happened.  Meshing those two steps seems like an obvious choice
>>>> to me.
>>>
>>>
>>>
>>> What I do is redefine the implementation of assert to do:
>>>
>>>  *(cast(int *)0) = 0;
>>>
>>> That way, I get a segmentation fault and a core dump that the debugger (gdb) is able to use to present me with a back trace and (all) local variables available for inspection. This is immensely more useful than letting assert throw an exception, which means losing all state and stack trace information.
>>>
>>> /Oskar
>>
>>
>>
>> And therein lies the key: what everyone is asking for is a means to capture additional state with the assert()
>>
>> Ideally, all code-testing would be performed within the comforting arms of a debugger. But it doesn't happen that way and, due to Murphy's law, the one and only time your code trips up is when it's not in the debugger. That's when you need additional state to help track things down; especially with those "non repeatable" bugs.
>>
>> Having said that, a very large part of the valuable state is the stack-trace ~ "how did we get here" can be just as important as some key variable. Often more so. Thus, I tend to look at assert as the bare minimum of tools; scraping the barrel, if you will. That goes to show how poor the runtime diagnostic support really is in D at this time ~ we're actually better off with printf() than most anythng else :)
>>
>> Thus when all is said and done, having support for a stack-trace seems far more valuable than the 'convenience' of an assert message. Although in the absence of the former, it's easy to see why assert() gets so much attention.
>>
>> Finally, I suspect adding printf formatting to assert() would be binding complexity at a delicate level; partly because the formatting might try to allocate memory?
>>
>> Let's get stack-tracing supported, instead of depending upon the marginally useful assert() statement :D
>>
>> - Kris
> 
> I'm sorry but I really have to insert my skepticism here about stack traces.
> 
> Upon first glance it sounds like a wonderful idea, until you get to where Java is at.  Literally hundreds of lines of stack traces dumped into log files to wade thru, most of them completely useless because: THEY DON'T CONTAIN STATE!!!

> Sure they have the call-stack state so you can see where the function calls came from but there are no local variables, no function parameter values, no class/struct dumps; basically nothing useful for anything more complex than the simplest case of a deterministic function call, and even then it's not too terribly useful.


> While I agree that it is better than nothing, we can still do better. An entire run-time debugging framework is what we really want to shoot for.  Exception logging, tracing, dumping of object contents, reading local variables, reading function parameters, etc.  This probably requires the help of a compile-time reflection system (where certain properties of objects are translated by the compiler into literal expressions).  Run-time reflection isn't really necessary.


I have to disagree with this. A stack trace does give you the most important piece of state information: the value of function pointers and delegates that are called. Personally, I don't think I've ever learnt much from a debugger other than seeing the call stack; it gives a list of all the places to look at for bugs (and the places to put more asserts into!). It covers >90% of the use cases.
June 02, 2006
I use:

static assert ("Message", 0);

Which gives a message similar to:

static assert  ("Message" , 0) is false

-[Unknown]


> My code is littered with:
> 
> static if (!cond) {
>   pragma(msg, "xxx");
>   static assert(0);
> }
June 02, 2006
In article <e5odr1$2mis$1@digitaldaemon.com>, James Dunne says...
>
[...]
>
>I'm sorry but I really have to insert my skepticism here about stack traces.
>
>Upon first glance it sounds like a wonderful idea, until you get to where Java is at.  Literally hundreds of lines of stack traces dumped into log files to wade thru, most of them completely useless because: THEY DON'T CONTAIN STATE!!!
>

A lot of state can be gained with scope(failure) statements. I have a program
where (as an experiment) every function is prefaced with:

# scope(failure) writef("StackTrace@"__FILE__":"~itoa!(__LINE__)~\n);

If I needed some state a few more scope(failure) line would do this quite
nicely.

I will grant, just an automated stack trace might not be to useful, but throwing in parameter values, called from info (line#) and the like would give you a good idea where things stand.

OTOH if I was trying to run an automated bug tracking system that gets reports from crashed sessions, a stack trace would be exactly where I would start.


>Sure they have the call-stack state so you can see where the function calls came from but there are no local variables, no function parameter values, no class/struct dumps; basically nothing useful for anything more complex than the simplest case of a deterministic function call, and even then it's not too terribly useful.
>
>While I agree that it is better than nothing, we can still do better. An entire run-time debugging framework is what we really want to shoot for.  Exception logging, tracing, dumping of object contents, reading local variables, reading function parameters, etc.  This probably requires the help of a compile-time reflection system (where certain properties of objects are translated by the compiler into literal expressions).  Run-time reflection isn't really necessary.
>
>-- 
>Regards,
>James Dunne


July 31, 2006
In article <e5l5v8$1g7j$1@digitaldaemon.com>,
 Tom S <h3r3tic@remove.mat.uni.torun.pl> wrote:

> Lars Ivar Igesund wrote:
> > Because not all the users will have access to the source, or be inclined to see it. Unless the user get's a readable/understandable assert message he/she might not get enough information to actually reproduce a test case for the developer to peruse.
> > 
> > Walter, this is a no-brainer, please put it in.
> 
> ++votes;
> 
> /+
> when you release your app to some testing team, you might want to leave
> asserts in. While an error message containing the line number and
> filename could be helpful, an additional message could be priceless.
> E.g. assert(fileNameContainsNoSpaces(foo)); won't tell you that the
> 'foo' really was something like '^&^34 5+23 3(43D678[SAFer6_[]' which
> might mean some mem corruption or forgetting a .dup somewhere in your
> code. You'd instead go searching for some logic problems that wouldn't
> solve the problem.
> +/

I vote for the assert(condition, "msg"), construct as well.

CXX Test and JUnit have spoiled me.  You can't even do assert(1 == 0 && "The laws of math have been changed"), which is trick I use in the C++ all the time.  Is having a message with the assert going to hurt anything?

-Joseph Lisee