How and When Should I Use On.Exit

Should we use exit() in C?

Rather than abort(), the exit() function in C is considered to be a "graceful" exit.

From C11 (N1570) 7.22.4.4/p2 The exit function (emphasis mine):

The exit function causes normal program termination to occur.

The Standard also says in 7.22.4.4/p4 that:

Next, all open streams with unwritten buffered data are flushed, all
open streams are closed, and all files created by the tmpfile function
are removed.

It is also worth looking at 7.21.3/p5 Files:

If the main function returns to its original caller, or if the exit
function is called, all open files are closed (hence all output
streams are flushed) before program termination. Other paths to
program termination, such as calling the abort function, need not
close all files properly.

However, as mentioned in comments below you can't assume that it will cover every other resource, so you may need to resort to atexit() and define callbacks for their release individually. In fact it is exactly what atexit() is intended to do, as it says in 7.22.4.2/p2 The atexit function:

The atexit function registers the function pointed to by func, to be
called without arguments at normal program termination.

Notably, the C standard does not say precisely what should happen to objects of allocated storage duration (i.e. malloc()), thus requiring you be aware of how it is done on particular implementation. For modern, host-oriented OS it is likely that the system will take care of it, but still you might want to handle this by yourself in order to silence memory debuggers such as Valgrind.

Python exit commands - why so many and when should each be used?

The functions* quit(), exit(), and sys.exit() function in the same way: they raise the SystemExit exception. So there is no real difference, except that sys.exit() is always available but exit() and quit() are only available if the site module is imported (docs).

The os._exit() function is special, it exits immediately without calling any cleanup functions (it doesn't flush buffers, for example). This is designed for highly specialized use cases... basically, only in the child after an os.fork() call.

Conclusion

  • Use exit() or quit() in the REPL.

  • Use sys.exit() in scripts, or raise SystemExit() if you prefer.

  • Use os._exit() for child processes to exit after a call to os.fork().

All of these can be called without arguments, or you can specify the exit status, e.g., exit(1) or raise SystemExit(1) to exit with status 1. Note that portable programs are limited to exit status codes in the range 0-255, if you raise SystemExit(256) on many systems this will get truncated and your process will actually exit with status 0.

Footnotes

* Actually, quit() and exit() are callable instance objects, but I think it's okay to call them functions.

Is there a way to run an expression on.exit() but only if completes normally, not on error?

Just wrap the args of all your return function calls with the code that you want done. So your example becomes:

foo = function(thing){do something; return(thing)}
myfunction = function() {
...
if (...) then return( foo(point 1) )
...
if (...) then return( foo(point 2) )
...
if (...) then return( foo(point 3) )
...
return ( foo(point 4) )
}

Or just make each then clause into two statements. Using on.exit to lever some code into a number of places is going to cause spooky action-at-a-distance problems and make the baby Dijkstra cry (read Dijkstra's "GOTO considered harmful" paper).

R: on.exit - use returned value without knowing its name

Since R 3.2.0 it is fully possible, thanks to new function returnValue.
Working example below.

f <- function(x, err = FALSE){
pt <- proc.time()[[3L]]
on.exit(message(paste("proc.time:",round(proc.time()[[3L]]-pt,4),"\nnrow:",as.integer(nrow(returnValue()))[1L])))
Sys.sleep(0.001)
if(err) stop("some error")
return(x)
}
dt <- data.frame(a = 1:5, b = letters[1:5])
f(dt)
f(dt, err=T)
f(dt)
f(dt[dt$a %in% 2:3 & dt$b %in% c("c","d"),])

Example of on.exit, add argument

Here is a very simple example

myfun <- function(x){
on.exit(print("first"))
on.exit(print("second"), add = TRUE)
return(x)
}

myfun(2)
#[1] "first"
#[1] "second"
#[1] 2

Also note what happens without the add=TRUE parameter

fun <- function(x){
on.exit(print("first"))
on.exit(print("second"))
return(x)
}

fun(2)
#[1] "second"
#[1] 2

The second call to on.exit removes the first call if you don't add the "add=TRUE".

Should I end my PHP script with exit or exit;?

exit, exit;, exit(), and exit(); are exactly the same, but the fact is that you should not end your script with an exit() call, it's just bad practice (but it works).

EDIT

Clarifying why i said it's "bad practice", it's not about the functionality of "exit" itself, it's OK to halt the script execution if something bad happens, but the concept of "something bad" is really wide. In general, even if some unwanted condition occurs, the normal execution flow should reach to the end of the file. Just consider this example:

...some init stuff...
if (!user_is_authenticated) {
...print some nasty message...
exit();
}
...continue with normal stuff...

A better approach would be:

...some init stuff...
if (user_is_authenticated) {
...continue with normal stuff...
}
else {
...print some nasty message...
}

What's the difference? The difference is that in the second version you don't need to use exit(), which means if one day you need to do something after BOTH the "normal" and "unwanted" execution flows you can just add it at the end of the file.

It's more or less the same argument about why you should NOT use "return" in function bodies except at the end of the function..



Related Topics



Leave a reply



Submit