Issue 13543 - std.file.FileException has useless __FILE__ and __LINE__ arguments tacked on
Summary: std.file.FileException has useless __FILE__ and __LINE__ arguments tacked on
Status: NEW
Alias: None
Product: D
Classification: Unclassified
Component: phobos (show other issues)
Version: D2
Hardware: All All
: P4 enhancement
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-09-27 20:16 UTC by Walter Bright
Modified: 2024-12-01 16:22 UTC (History)
6 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Walter Bright 2014-09-27 20:16:47 UTC
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 bearophile_hugs 2014-09-27 20:46:22 UTC
I guess a FileException should give the line number of the *user* code where he/she has performed a failed file operation.
Comment 2 Walter Bright 2014-09-27 21:37:38 UTC
(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 bearophile_hugs 2014-09-27 21:46:20 UTC
(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 Walter Bright 2014-09-27 22:32:50 UTC
(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 bearophile_hugs 2014-09-27 22:35:41 UTC
(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 bearophile_hugs 2014-09-27 22:40:09 UTC
(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 Walter Bright 2014-09-27 22:47:21 UTC
(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 bearophile_hugs 2014-09-27 22:58:45 UTC
(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 Walter Bright 2014-09-27 23:25:56 UTC
(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 Walter Bright 2014-09-27 23:28:34 UTC
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 bearophile_hugs 2014-09-28 00:04:33 UTC
(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 Brad Anderson 2014-09-28 01:05:09 UTC
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 Ketmar Dark 2014-09-28 01:47:31 UTC
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 Stewart Gordon 2014-09-28 21:47:49 UTC
(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 bearophile_hugs 2014-09-28 23:31:30 UTC
(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 Ketmar Dark 2014-09-29 00:51:43 UTC
(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 ===

;-)
Comment 17 Martin Nowak 2014-09-29 03:14:38 UTC
The file and line information is an inherent part of our Throwable class, so of course everyone is forwarding __FILE__ and __LINE__ [1].
We could replace the location info by teaching stack traces how to read debug info, see bug 11870.

[1]: https://github.com/D-Programming-Language/druntime/blob/36736e430b0c5299cf2ab9875be3b36236185f3b/src/object.di#L321
Comment 18 Stewart Gordon 2014-09-29 12:29:49 UTC
(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 bearophile_hugs 2014-09-29 13:18:37 UTC
(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 Stewart Gordon 2014-09-29 18:18:34 UTC
(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 dlangBugzillaToGithub 2024-12-01 16:22:32 UTC
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/phobos/issues/10088

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB