September 28, 2014
On Sat, 27 Sep 2014 16:15:40 -0700
Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:

> After all, what would you think of a compiler that spewed out messages like this:
> 
>     > dmd test.d
>     test.d(15) Error: missing } thrown from dmd/src/parse.c(283)
> 
> ?
"wow, that's cool! one more pleasing feature!"


September 28, 2014
On 9/27/2014 6:24 PM, Steven Schveighoffer wrote:
> On 9/27/14 7:15 PM, Walter Bright wrote:
>
>> When I say "They are NOT for debugging programs", I mean they are NOT
>> for debugging programs.
>
> Library code often cannot make that choice.
> The issue with exceptions vs. errors
> is that often you don't know where the input comes from.
>
> e.g.:
>
> auto f = File(someInternalStringThatIsCorrupted) -> error
> auto f = File(argv[1]) -> exception
>
> How does File know what it's target file name came from?

If the app is concerned about invalid filenames as bugs, you should scrub the filenames first. I.e. the interface is defined improperly if the code confuses a programming bug with input errors.



September 28, 2014
On 2014-09-28 03:24, Steven Schveighoffer wrote:

> Library code often cannot make that choice. The issue with exceptions
> vs. errors is that often you don't know where the input comes from.
>
> e.g.:
>
> auto f = File(someInternalStringThatIsCorrupted) -> error
> auto f = File(argv[1]) -> exception
>
> How does File know what it's target file name came from?

Both of theses should throw an exception. Most stuff related to file operations should throw an exception, not an error.

-- 
/Jacob Carlborg
September 28, 2014
On 28.9.2014. 1:15, Walter Bright wrote:
> This issue comes up over and over, in various guises. I feel like
> Yosemite Sam here:
>
>      https://www.youtube.com/watch?v=hBhlQgvHmQ0
>
> In that vein, Exceptions are for either being able to recover from
> input/environmental errors, or report them to the user of the application.
>
> When I say "They are NOT for debugging programs", I mean they are NOT
> for debugging programs.
>
> assert()s and contracts are for debugging programs.
>
> After all, what would you think of a compiler that spewed out messages
> like this:
>
>     > dmd test.d
>     test.d(15) Error: missing } thrown from dmd/src/parse.c(283)
>
> ?
>
> See:
>
>      https://issues.dlang.org/show_bug.cgi?id=13543
>
> As for the programmer wanting to know where the message "missing }" came
> from,
> li
>      grep -r dmd/src/*.c "missing }"
>
> works nicely. I do that sort of thing all the time. It really isn't a
> problem.

We has this issue at work (we are working with php). We outputted a stack trace for both exceptions and asserts but the lines that should be addressed are not always so obvious.

I found a solution and it works great for us. All library code is marked appropriately so when stack is outputted it is shadows out (with gray color) all the lines in library code and point out first non-library line from the top of the stack. In 95% of the time it is the line that the programmer should look into. Other 5% is the time when it shows the line where programmer is forwarding a call to the library but turns out to be ok as it turns out to be much more comprehensible than the entire stack. One note worth mentioning is that juniors have much easier time understanding which lines concern them, and from that I can only conclude that such approach is more intuitive.

Marking is done on namespace level so it can be easily disabled for entire namespace.

I think outputting a stack trace for asserts is a must because of that 5%. And for exceptions I agree completely with your arguments and I think that there is no need for stack.

From my experience this has been a good approach and I think is worth considering.

September 28, 2014
luka8088:

> All library code is marked appropriately so when stack is outputted it is shadows out (with gray color) all the lines in library code and point out first non-library line from the top of the stack. In 95% of the time it is the line that the programmer should look into. Other 5% is the time when it shows the line where programmer is forwarding a call to the library but turns out to be ok as it turns out to be much more comprehensible than the entire stack. One note worth mentioning is that juniors have much easier time understanding which lines concern them, and from that I can only conclude that such approach is more intuitive.

This looks like a little enhancement request, to colourize differently the parts of the stack trace of the library code/runtime from the user code.


> And for exceptions I agree completely with your arguments and I think that there is no need for stack.

I think Walter is not suggesting to remove the stack trace for exceptions.

Bye,
bearophile
September 28, 2014
On 9/27/14, 8:15 PM, Walter Bright wrote:
> This issue comes up over and over, in various guises. I feel like
> Yosemite Sam here:
>
>      https://www.youtube.com/watch?v=hBhlQgvHmQ0
>
> In that vein, Exceptions are for either being able to recover from
> input/environmental errors, or report them to the user of the application.
>
> When I say "They are NOT for debugging programs", I mean they are NOT
> for debugging programs.
>
> assert()s and contracts are for debugging programs.

For me, assert is useless.

We are developing a language using LLVM as our backend. If you give LLVM something it doesn't like, you get something this:

~~~
Assertion failed: (S1->getType() == S2->getType() && "Cannot create binary operator with two operands of differing type!"), function Create, file Instructions.cpp, line 1850.

Abort trap: 6
~~~

That is what the user gets when there is a bug in the compiler, at least when we are generating invalid LLVM code. And that's one of the good paths, if you compiled LLVM with assertions, because otherwise I guess it's undefined behaviour.

What I'd like to do, as a compiler, is to catch those errors and tell the user: "You've found a bug in the app, could you please report it in this URL? Thank you.". We can't: the assert is there and we can't change it.

Now, this is when you interface with C++/C code. But inside our language code we always use exceptions so that programmers can choose what to do in case of an error. With assert you loose that possibility.

Raising an exception is costly, but that should happen in exceptional cases. Installing an exception handler is cost-free, so I don't see why there is a need for a less powerful construct like assert.
September 28, 2014
On Sunday, 28 September 2014 at 00:40:26 UTC, Walter Bright wrote:
>
> Whoa, Camel! You're again thinking of Exceptions as a debugging tool.

They can be.  What if an API you're using throws an exception you didn't expect, and therefore don't handle?  This might be considered a logic error if the exception is recoverable and you don't intend the program to abort from that operation.
September 28, 2014
On Sunday, 28 September 2014 at 16:16:09 UTC, Sean Kelly wrote:
> On Sunday, 28 September 2014 at 00:40:26 UTC, Walter Bright wrote:
>>
>> Whoa, Camel! You're again thinking of Exceptions as a debugging tool.
>
> They can be.  What if an API you're using throws an exception you didn't expect, and therefore don't handle?  This might be considered a logic error if the exception is recoverable and you don't intend the program to abort from that operation.

Also, I think the idea that a program is created and shipped to an end user is overly simplistic.  In the server/cloud programming world, when an error occurs, the client who submitted the request will get a response appropriate for them and the system will also generate log information intended for people working on the system.  So things like stack traces and assertion failure information is useful even for production software.  Same with any critical system, as I'm sure you're aware.  The systems are designed to handle failures in specific ways, but they also have to leave a breadcrumb trail so the underlying problem can be diagnosed and fixed.  Internal testing is never perfect, and achieving a high coverage percentage is nearly impossible if the system wasn't designed from the ground up to be testable in such a way (mock frameworks and such).
September 28, 2014
On Sunday, 28 September 2014 at 15:10:26 UTC, Ary Borenszweig wrote:
>
> What I'd like to do, as a compiler, is to catch those errors and tell the user: "You've found a bug in the app, could you please report it in this URL? Thank you.". We can't: the assert is there and we can't change it.
>

Why is SIGABRT handler not working for your usecase? print and exit?
September 28, 2014
On 9/28/2014 9:16 AM, Sean Kelly wrote:
> On Sunday, 28 September 2014 at 00:40:26 UTC, Walter Bright wrote:
>>
>> Whoa, Camel! You're again thinking of Exceptions as a debugging tool.
>
> They can be.

Of course they can be. But it's inappropriate to use them that way, and we should not be eschewing such in the library.

> What if an API you're using throws an exception you didn't expect,
> and therefore don't handle?

Then the app user sees the error message. This is one of the cool things about D - I can write small apps with NO error handling logic in it, and I still get appropriate and friendly messages when things go wrong like missing files.

That is, until recently, when I get a bunch of debug stack traces and internal file/line messages, which are of no use at all to an app user and look awful.

> This might be considered a logic error if the
> exception is recoverable and you don't intend the program to abort from that
> operation.

Adding file/line to all exceptions implies that they are all bugs, and encourages them to be thought of as bugs and debugging tools, when they are NOT. Exceptions are for:

1. enabling recovery from input/environmental errors
2. reporting input/environmental errors to the app user
3. making input/environmental errors not ignorable by default

They are not for detecting logic errors. Assert is designed for that.