-
Notifications
You must be signed in to change notification settings - Fork 173
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handling runtime errors/exceptions #212
Comments
Very nice description and, FWIW, I prefer approach 3 as well. One problem that I have faced a few times in the design of such routines is how this API communicates when nested at multiple levels of depth. Say the user is running a numerical integrator within a root-finding problem that is, in turn, used to solve a system of a differential equations. We might have three levels of depth in this case (admittedly, probably rare and fictitious), but I have personally used (within the scope of |
One thing that we should try to avoid is to force every user to be checking every single function from stdlib to ensure it succeeded. We should figure out how to allow users to check it if they want to and handle the error themselves, but we should also allow users to just call a given So I would say a combination of 3. and 1. is the way to go. The option 2. should be combined with the option 1. I.e., if the optional The option 3. is great for functions such as |
Thank you for these clear propositions. It is related to #95 too. The options 1., 2., and 3. could be used for different purposes/procedures. For example, returning |
There are two related questions raised by @nshaffer original post:
To address the first question I have written a module, that I have tentatively named STDLIB_ERROR_REPORTING, and a markdown document describing the module's API in some detail. The module consists of a number of named constants and five subroutines. The module defines 80+ unique named constants to serve as error codes for reporting errors in a consistent manner. The constants can be defined as integers or a derived type, but are currently defined as a derived type named
Four of the five subroutines have ASSERT( TEST, MESSAGE [, MODULE, PROCEDURE, ERROR ] ): If REPORT_ERROR( MESSAGE [, MODULE, PROCEDURE, STAT, ERRMSG, ERROR ] ): Writes the character string, REPORT_IO_ERROR( MESSAGE [, MODULE, PROCEDURE, IOSTAT, IOMSG, ERROR ] ): Writes the character string, REPORT_TEXT_ERROR( LINE, START_INDEX, DESCRIP [, FILENAME, LINE_NUMBER, WRITE_UNIT, ERROR ] ): Sends a message to SEND_STOP( ERROR ): Stops processing with an As to the second question as to what guidelines programmers should follow I have a few strong opinions on user and memory allocation errors and pure procedures. Programmers should not report user errors up the call chain. They should simply stop with an informative message, or if purity or elemental attributes are important and F2008 compatibility is important, they should do nothing at all. Programmers should almost never attempt to handle memory allocation problems. With virtual memory, allocation should almost never fail, and with lazy allocation on Linux, failure need not be discovered at the invocation of an
Finally as to purity, there is currently nothing to be done to handle errors in F2018 for |
FWIW here is some example code illustrating how I view the module being used:
|
@wclodius2 Thank you for the carefully considered post. I hope you can clarify a few things for me about your approach.
|
@wclodius2 , your example usage looks very similar to a library I developed: erloff I don't have the routines that output the errors and stop the program, but those are easy to add. |
@nshaffer thank you for your kind words.
|
@everythingfunctional I'm glad I am not the only one that approaches error handling this way. |
Wrt the error codes defined in ISO_FORTRAN_ENV we could use code like this
to ensure that the error codes in the library do not interfere with the
predefined ones for any processor:
! errorcodes.f90 --
! Use simple calculations to ensure a range outside all predefined
error codes
!
program errorcodes
use iso_fortran_env
integer, parameter :: error_base = 1 + max(abs(iostat_end),
abs(iostat_eor), abs(iostat_inquire_internal_unit) ) ! TODO: add the STAT_*
codes
write(*,*) error_base
end program errorcodes
Out of laziness I have left out the STAT_* error codes :). The program is
accepted by both gfortran and Intel Fortran and produces two very different
values, 5019 and 91, respectively.
Regards,
Arjen
Op zo 12 jul. 2020 om 23:32 schreef William B. Clodius <
[email protected]>:
… @nshaffer <https://github.com/nshaffer> thank you for your kind words.
1.
Thank you for reminding me of the error flags in ISO_FORTRAN_ENV. It
has given me a few more error
codes to add to my initial list of eighty two. The one problem with
the ISO_FORTRAN_ENV flags is that
their values can vary arbitrarily between processors, so if you want
to pass status flags for multiple
categories of problems, ensuring that your values are different for
each cause requires replacing their
values with your own any way.
2.
It is expected that the writer of the routine that reports the errors
to the user documents what errors
it passes, that the user decides whether he wants to handle any of
them or let failure occur in the
called routine, and that the user decide which errors he wants to
handle or let fail in the calling routine.
I have tried to be very thorough in identifying categories of errors.
If a user decides that none of the
codes are suitable they can do any of: ask me to add an appropriate
error code; if the code were
added to the standard library he could add them himself, use the
generic FAILURE code; or define
their own (presumably integer) flags and document them.
3.
I think a standard library should formalize its error reporting so
that users have a consistent interface.
As a starting point, I think that having utility routines that report
the location of the errors are useful.
I want to contribute to the library, but don't want each module to
have its own error reporting.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#212 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAN6YRYAUBOTHIYVDT2SVMTR3ITV3ANCNFSM4N4KVJSA>
.
|
FWIW my version of gfortran (10.1.0 on the Mac) doesn't define the most recent addition to ISO_FORTRAN_ENV, STAT_FAILED_IMAGE, so an enumeration of error codes that included those defined in ISO_FORTRAN_ENV beyond the I/O ones would have to be processor specific. However, there doesn't seem to be much interest in an enumeration of error codes, whether or not they included those in ISO_FORTRAN_ENV. If there is I could post my enumeration as a starting point. |
Re gfortran 10.1 not defining STAT_FAILED_IMAGE: I was afraid of that
;). And there doesn't seem to be a way to provide a fallback value.
Regards,
Arjen
Op ma 13 jul. 2020 om 15:42 schreef William B. Clodius
<[email protected]>:
…
FWIW my version of gfortran (10.1.0 on the Mac) doesn't define the most recent addition to ISO_FORTRAN_ENV, STAT_FAILED_IMAGE, so an enumeration of error codes that included those defined in ISO_FORTRAN_ENV beyond the I/O ones would have to be processor specific. However, there doesn't seem to be much interest in an enumeration of error codes, whether or not they included those in ISO_FORTRAN_ENV. If there is I could post my enumeration.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or unsubscribe.
|
This issue is to discuss approaches to handle runtime errors and exceptions in stdlib. I have in mind scenarios such as
These are conditions which cannot be identified at compile time, but if left alone will either cause user code to crash or be erroneous. Currently in stdlib, we have
check
, which can print error messages and optionally terminate execution. I think it is not sufficient for general-purpose runtime checking. To me, there are a few major considerations when thinking about runtime checkingUsers must be given the opportunity to recover from the error if at all possible. This is especially important for library code, which may be difficult to debug depending on the installation/distribution. It is also generally rude for library code to kill execution without giving the user any say in the matter.
It should be possible to recover from runtime errors without sacrificing purity. If a routine is manifestly pure, then it should not have to sacrifice the
pure
attribute just to have some error checking. If I write a factorial function, making itpure
and handling negative arguments should not have to be an either/or proposition.Checking and handling errors should not be unduly burdensome to users. If a function call requires one line, and handling its possible error conditions requires ten, users will simply not bother with error checking.
This list of criteria is not exhaustive, but they are the three that are most important to me. That stated, here are the runtime checking approaches I am most familiar with and how they stack up:
Return error code and message as optional out-params.
iostat
,iomsg
)Die with
error stop
Return a special value
index
returning -1Raise an exception
Of these, my preference is strongly toward approach 3 whenever possible.
The text was updated successfully, but these errors were encountered: