@AllanCamerons answer already answers my question in a very elegant way. However, there's one problem that kept bugging me: The function signals both a message and an error. After studying the source code of rlang::signal_abort(), I found that a mix of signalCondition() and cat() mostly mirrors the behavior of rlang::abort():
abort <- function(msg, call = sys.call(1)) {
cnd <- errorCondition(msg, call = call)
signalCondition(cnd)
msg <- sprintf("Error in %s:\n- %s", deparse(call), msg)
cat(msg, "\n", file = stderr())
old_options <- options(show.error.messages = FALSE)
on.exit(options(old_options))
stop("")
}
What (I think) this does:
signalCondition(cnd) is where the error condition is signaled and specifies the "official" error message (as caught condition handlers) but does not abort execution.cat(..., file = stderr()) prints to stderr but does not signal a message.stop("") aborts execution but neither signals another error (as this is already done earlier) nor prints an error message (as it is suppressed).Why this is useful:
> tryCatch(abort("something went wrong"), message = \(e) "message caught!")
# Error in tryCatch(abort("something went wrong"), message = function(e) "message caught!"):
# - something went wrong
> tryCatch(abort("something went wrong"), error = \(e) "error caught!")
# [1] "error caught!"
> try(abort("something went wrong"))
# Error : something went wrong