I take exception (!) to this notion. As a computer user (not
a programmer) what would one think about error messages from an
application that printed file and line of something internal to the
app's source code? WTF, right? FileException is being
confused here with being a programmer debugging tool. It is NOT.
Exceptions are not for debugging programming errors. They're for
reporting on input errors. They're being confused with asserts here.
Comment #1 by bearophile_hugs — 2014-09-27T20:46:22Z
I guess a FileException should give the line number of the *user* code where he/she has performed a failed file operation.
Comment #2 by bugzilla — 2014-09-27T21:37:38Z
(In reply to bearophile_hugs from comment #1)
> I guess a FileException should give the line number of the *user* code where
> he/she has performed a failed file operation.
Once again, Exceptions are NOT for debugging user code.
Comment #3 by bearophile_hugs — 2014-09-27T21:46:20Z
(In reply to Walter Bright from comment #2)
> (In reply to bearophile_hugs from comment #1)
> > I guess a FileException should give the line number of the *user* code where
> > he/she has performed a failed file operation.
>
> Once again, Exceptions are NOT for debugging user code.
I don't agree. If I open a file, and the opening fails, I'd like the exception to tell me what damned line of my code has tried to open that file. Exceptions are useful to debug user code.
Comment #4 by bugzilla — 2014-09-27T22:32:50Z
(In reply to bearophile_hugs from comment #3)
> (In reply to Walter Bright from comment #2)
> > Once again, Exceptions are NOT for debugging user code.
>
> I don't agree. If I open a file, and the opening fails, I'd like the
> exception to tell me what damned line of my code has tried to open that
> file. Exceptions are useful to debug user code.
This is a serious misuse of Exceptions.
What do your customers think when your apps are showing them file/line pointing to your internal source code when a file doesn't exist?
I've never even heard of an app that would assault users with such "error" messages, except for D apps.
The construct to debug code is "assert", not "throw".
Cue my usual rant about confusion between what is a programming logic error and what is an input/environmental error, and the conflation of the methods for dealing with them.
Comment #5 by bearophile_hugs — 2014-09-27T22:35:41Z
(In reply to bearophile_hugs from comment #3)
> If I open a file, and the opening fails, I'd like the
> exception to tell me what damned line of my code has tried to open that
> file.
- - - - - - - - - - - - - - -
A Python script (both files are missing):
f1 = open("some_file1.txt")
f2 = open("some_file2.txt")
Gives information that helps to locate what's the line that has tried to open the missing file:
Traceback (most recent call last):
File "...\test.py", line 1, in <module>
f1 = open("some_file1.txt")
IOError: [Errno 2] No such file or directory: 'some_file1.txt'
- - - - - - - - - - - - - - -
A similar D program gives line number inside the library code, but I'd like an exception that tells me that the problem is in test.d at line 3:
void main() {
import std.stdio;
auto f1 = File("some_file1.txt");
auto f2 = File("some_file2.txt");
}
std.exception.ErrnoException@std\stdio.d(364): Cannot open file `some_file1.txt' in mode `rb' (No such file or directory)
----------------
0x0040447B in @safe shared(core.stdc.stdio._iobuf)* std.exception.__T12errnoEnforceTPOS4core4stdc5stdio6_iobufVAyaa11_7374645c737464696f2e64Vki364Z.errnoEnforce(shared(core.stdc.stdio._iobuf)*, lazy immutable(char)[])
...
- - - - - - - - - - - - - - -
Comment #6 by bearophile_hugs — 2014-09-27T22:40:09Z
(In reply to Walter Bright from comment #4)
> This is a serious misuse of Exceptions.
>
> What do your customers think when your apps are showing them file/line
> pointing to your internal source code when a file doesn't exist?
It's a basic information, better than no information at all. If my app tells me a file is missing then maybe I can find it. But see below.
> I've never even heard of an app that would assault users with such "error"
> messages, except for D apps.
>
>
> The construct to debug code is "assert", not "throw".
Adding the line number of the user code that has caused the IO exception is handy to fix little script-like D programs.
A IO exception is meant to be caught by your large serious programs, it's never meant to be shown to users.
Comment #7 by bugzilla — 2014-09-27T22:47:21Z
(In reply to bearophile_hugs from comment #6)
> A IO exception is meant to be caught by your large serious programs, it's
> never meant to be shown to users.
1. You are trying to use exceptions to debug the program. This is utterly wrong.
2. Exceptions are meant to provide information to the user of the app, not the programmer of the app.
Comment #8 by bearophile_hugs — 2014-09-27T22:58:45Z
(In reply to Walter Bright from comment #7)
> 1. You are trying to use exceptions to debug the program. This is utterly
> wrong.
It's what millions of people are doing every day in Python, Ruby, etc. If you are writing a 50 lines long script program that loads some files, you are thankful when the exception tells you what line of your code has opened a missing file.
In such small D programs you don't want to add assert(isOpen(...) && isWriteable(...)) and even if you do that, there are other problems, like asserts and file ops getting out of sync, file state changing between the assert and the file operation, etc.
> 2. Exceptions are meant to provide information to the user of the app, not
> the programmer of the app.
As an user of the app, the app should tell me that a file is missing with a nice pop up window, or better, not with exceptions. But not all D programs are large, and giving the line number in the exception message is a first basic information when the code has bugs or when the D program is not an app, but a little script-like (and I write many such tiny D programs).
Comment #9 by bugzilla — 2014-09-27T23:25:56Z
(In reply to bearophile_hugs from comment #8)
> It's what millions of people are doing every day in Python, Ruby, etc. If
> you are writing a 50 lines long script program that loads some files, you
> are thankful when the exception tells you what line of your code has opened
> a missing file.
I doubt I'd have trouble locating a 'throw' statement in a 50 line program. I don't believe you would, either.
> In such small D programs you don't want to add assert(isOpen(...) &&
> isWriteable(...)) and even if you do that, there are other problems, like
> asserts and file ops getting out of sync, file state changing between the
> assert and the file operation, etc.
Sorry, I think this is rubbish. (You also do not want to catch Exception messages just to filter out the file/line to then present the message to the user.)
> > 2. Exceptions are meant to provide information to the user of the app, not
> > the programmer of the app.
>
> As an user of the app, the app should tell me that a file is missing with a
> nice pop up window,
Console apps don't need to that, and it's pretty easy for a gui app to provide a top level handler that pops up a window.
> or better, not with exceptions. But not all D programs
> are large, and giving the line number in the exception message is a first
> basic information when the code has bugs
Again, Exceptions are NOT A DEBUGGING TOOL and should NOT BE THROWN WHEN BUGS ARE DETECTED. Use asserts for that. Asserts are designed for that, and are pretty good at it.
Comment #10 by bugzilla — 2014-09-27T23:28:34Z
To put things more clearly, Exceptions are for:
1. so code can recover cleanly from input/environmental errors
2. if (1) is not possible, report the error to the app user in a manner that is sensible to the app user
They are NOT for:
1. so the code can recover from internal programming bugs
2. reporting internal programming bugs to the app user
Comment #11 by bearophile_hugs — 2014-09-28T00:04:33Z
(In reply to Walter Bright from comment #9)
> I doubt I'd have trouble locating a 'throw' statement in a 50 line program.
> I don't believe you would, either.
Often there is no throw statement in the user code. See my answer in the newsgroup.
> Use asserts for that. Asserts are designed for that, and
> are pretty good at it.
Have you seen asserts used to pre-test I/O actions in D script-like programs? I've never seen them in the wild. Large programs catch exceptions and offer meaningful error messages, windows, etc. And script-like programs just show the exception and stack trace.
Comment #12 by eco — 2014-09-28T01:05:09Z
Generally speaking, the __FILE__/__LINE__ trick sounds like a perfect example of something you put in a Debug build and leave out of a Release build. It can be genuinely useful during development while the program's logic is still being hammered out but it's often not useful or desired to show this information to end users.
Comment #13 by ketmar — 2014-09-28T01:47:31Z
that's why i HATE "release builds". if "release build" crashes, it's a whole lot of hell to extract any useful info from the crash to fill bugreport.
the whole thing with "release builds" should die. program must not crash. period. but IF it crashed, it must spit out ALOT of info, line numbers, backtraces, various internal states, and so on. so developer will NEVER need to ask to "run thing debug build please, and try to reproduce the bug, 'cause i can't see where that message comes from and why." it's a PITA to ask users to do something like that.
Comment #14 by smjg — 2014-09-28T21:47:49Z
(In reply to Brad Anderson from comment #12)
> Generally speaking, the __FILE__/__LINE__ trick sounds like a perfect
> example of something you put in a Debug build and leave out of a Release
> build. It can be genuinely useful during development while the program's
> logic is still being hammered out but it's often not useful or desired to
> show this information to end users.
We already have this facility. It's called a stack trace.
Comment #15 by bearophile_hugs — 2014-09-28T23:31:30Z
(In reply to Stewart Gordon from comment #14)
> We already have this facility. It's called a stack trace.
If I run this:
void main() {
import std.stdio;
auto f1 = File("some_file1.txt");
auto f2 = File("some_file2.txt");
}
std.exception.ErrnoException@std\stdio.d(364): Cannot open file `some_file1.txt' in mode `rb' (No such file or directory)
----------------
0x0040445B in @safe shared(core.stdc.stdio._iobuf)* std.exception.__T12errnoEnforceTPOS4core4stdc5stdio6_iobufVAyaa11_7374645c737464696f2e64Vki364Z.errnoEnforce(shared(core.stdc.stdio._iobuf)*, lazy immutable(char)[])
0x00402406 in D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZ9__lambda1MFZv
0x004023DB in void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll()
0x004022F1 in _d_run_main
0x00402100 in main
0x00414C7D in mainCRTStartup
0x7732D3C9 in BaseThreadInitThunk
0x771B1603 in RtlInitializeExceptionChain
0x771B15D6 in RtlInitializeExceptionChain
Where's the line number 3 of the user code that fails to open the file?
Comment #16 by ketmar — 2014-09-29T00:51:43Z
(In reply to bearophile_hugs from comment #15)
> Where's the line number 3 of the user code that fails to open the file?
switch to GNU/Linux and GDC, gdc stacktrace knows how to decode debug info:
=== cut ===
0xb7462159 ref std.stdio.File std.stdio.File.__ctor(immutable(char)[], const(char[]))
../../../../gcc-4.9.1/libphobos/src/std/stdio.d:389
0x8049ce4 _Dmain
/tmp/z00.d:3
=== cut ===
;-)
(In reply to bearophile_hugs from comment #15)
> Where's the line number 3 of the user code that fails to open the file?
Good question. Did you compile in debug info (-g switch)? (I'm at work at the moment, so not in a position to try it myself and see.)
Comment #19 by bearophile_hugs — 2014-09-29T13:18:37Z
(In reply to Stewart Gordon from comment #18)
> Did you compile in debug info (-g switch)?
Yes, if you don't use -g the stack trace looks naked like:
std.exception.ErrnoException@std\stdio.d(367): Cannot open file `some_file1.txt' in mode `rb' (No such file or directory)
----------------
0x00403E23
0x00402F82
0x00402F57
0x00402E6D
0x004020FF
0x7798D3C9 in BaseThreadInitThunk
0x77B31603 in RtlInitializeExceptionChain
0x77B315D6 in RtlInitializeExceptionChain
Comment #20 by smjg — 2014-09-29T18:18:34Z
(In reply to Walter Bright from comment #9)
> Again, Exceptions are NOT A DEBUGGING TOOL and should NOT BE THROWN WHEN
> BUGS ARE DETECTED. Use asserts for that. Asserts are designed for that, and
> are pretty good at it.
I don't think anybody here is trying to use exceptions as a debugging tool. A bug might naturally manifest itself in the form of an exception being thrown. And when this happens, naturally the programmer will want to know what has triggered it. Of course, this is what the stack trace is for.
Comment #21 by robert.schadek — 2024-12-01T16:22:32Z