I don't throw an exception - a standard function does that. I'm actually handling it.
By using
TFileStream you are introducting a source of exceptions into your program.
Exceptions
were originally created to force programmers to handle errors, because often these programmers were sloppy and would not check function results.
Your
ReadDefaultConfig disables that mechanism by trying to return NIL in case of errors. You are basically fighting against the compiler/language. (Also, if you run your program from the IDE and an exception occurs, the IDE pops up and the program is halted until you manually continue it.)
The hypothetical "ReadDefaultConfig" function should return a TStream, while SysUtils.FileOpen returns a file handle.
There's
THandleStream that takes the handle in its constructor.
You can also open the file (e.g. with
FileOpen) to prevent it from being deleted by someone / some program, then open it with TFileStream, then close the original handle with FileClose. (This might only work on Windows; on Unix/Linux you may have to use
THandleStream.)
Well, as far as I know, calling a function creates a stack frame, and the function's result is passed through it. So, I assumed that when the function exits, it should still return something, which will be assigned to a variable.
The function never "exits" normally though, it's interrupted (the regular execution path has crashed). The exceptions mechanism (
which is not cheap) then cleans up the stack.
The user isn't required to know this anyway, so the documentation should explain it.
I disagree though, anyone using exceptions (which includes anyone using
TFileStream) should know/learn this.
(If you think the user isn't required to know this, why should they need an explanation in the documentation?)