TIP #221: ALLOW BACKGROUND ERROR HANDLERS TO ACCEPT RETURN OPTIONS ==================================================================== Version: $Revision: 2.10 $ Author: Don Porter State: Final Type: Project Tcl-Version: 8.5 Vote: Done Created: Wednesday, 15 September 2004 URL: https://tip.tcl-lang.org221.html Post-History: ------------------------------------------------------------------------- ABSTRACT ========== This TIP proposes a new system for registering a background error handler of an interp so that the full set of return options ([TIP #90]) can be passed to it. BACKGROUND ============ Whenever a script is evaluated as part of handling an event, and that script evaluation returns TCL_ERROR or some other non-TCL_OK return code it is not equipped to handle, then the code that evaluates that script is expected to call /Tcl_BackgroundError/ to report the exceptional code to the application. Then /Tcl_BackgroundError/ will arrange for the command *bgerror* to be called during an idle event. It is intended that each application will define a *::bgerror* command to its liking so that background errors are reported (or ignored) as the application prefers. The defined syntax for *bgerror* is *bgerror* /message/ The *bgerror* command receives as its only argument a copy of what the interp result was when /Tcl_BackgroundError/ was called. This is presumably an error message. When *bgerror* is called, it is also arranged that the variables *::errorInfo* and *::errorCode* are set to the same values they had when /Tcl_BackgroundError/ was called. This is effectively another set of arguments passed through a side channel. Note that the non-TCL_OK return code that triggered the /Tcl_BackgroundError/ call is not itself made known to *bgerror*. Nor is the /-level/, /-errorline/, or other return option information made possible by [TIP #90] passed along to *bgerror* in any way. PROPOSAL ========== A new subcommand, *interp bgerror* will be created that allows for registration of a handler command to react to background errors. Its syntax will be: *interp bgerror* /path/ ?/cmdPrefix/? Here /path/ is the path of an interp, interpreted the same way as the /path/ argument to the existing *interp aliases* subcommand. This argument determines which interp's background error handler we are interested in. The value of an empty list for /path/ indicates the current interp. As is the case with other *interp* subcommands, an alternative means to access the same functionality will be made available as the *bgerror* subcommand of the /slave/ command of an interp with syntax: /slave/ *bgerror* ?/cmdPrefix/? When no /cmdPrefix/ argument is present, the command prefix currently registered to handle background errors in the /path/ interp will be returned. The returned value will be the /cmdPrefix/ argument most recently successfully passed to *interp bgerror* /path/, or the default background error handler command of the interp. When a /cmdPrefix/ argument is present, it must be a valid Tcl list of length at least one. An invalid list or an empty list is an error. A /cmdPrefix/ list argument of length /N/ will become the first /N/ substituted words of the handler command invoked to handle calls to /Tcl_BackgroundError/. That is, if the /cmdPrefix/ argument is stored in a variable *cmdPrefix*, subsequent calls to /Tcl_BackgroundError/ will lead to evaluation of a command like so: *{expand}$cmdPrefix* /message/ /returnOptionsDictionary/ The /message/ argument is the interp result at the time /Tcl_BackgroundError/ is called. The /returnOptionsDictionary/ argument is a Tcl dict value ([TIP #111]) holding the value of the interp's return options dictionary at the time /Tcl_BackgroundError/ was called. Specifically, the /returnOptionsDictionary/ argument is the value returned by /Tcl_GetReturnOptions/ ([TIP #227]) at the time /Tcl_BackgroundError/ is called. Stored in the /returnOptionsDictionary/ argument will be values for the /-level/ and /-code/ keys, and when those values indicate a TCL_ERROR triggered the /Tcl_BackgroundError/ call, the /-errorinfo/, /-errorcode/, and /-errorline/ keys will have values as well. Any other return options present in the interp's return options dictionary at the time /Tcl_BackgroundError/ is called will also be available in the /returnOptionsDictionary/ argument. Note that after this change, applications will be able to register a background error handling command that has no need to consult the variables *::errorInfo* or *::errorCode* at all. COMPATIBILITY =============== Existing applications making use of the *bgerror* interface provide a *bgerror* command that expects exactly one argument. To continue to compatibly support these applications, the default background error handler command prefix registered in each interp will be a command that sets the values of *::errorInfo* and *::errorCode* to the values of the corresponding keys in the return options dictionary, if appropriate. Then it will invoke the command *bgerror* /message/ in the global namespace. For complete compatibility, the existing fallbacks will also be honored in the default handler, including the invoking a hidden command *bgerror* /message/ in safe interps, and the ultimate fallback (in trusted interps only) being a message written to the stderr channel of the process as determined by /Tcl_GetStdChannel(TCL_STDERR)/. REJECTED ALTERNATIVES ======================= The first draft of this proposal proposed several attempts to call *bgerror*, first with two arguments, then with one. It was rejected because an error due to calling *bgerror* with the wrong number of arguments could not be distinguished (easily and reliably) from an error for other reasons. This fallback strategy was prone to the masking of errors. The new proposal is also preferred over the first draft as it empowers Tcl programmers to leave behind *bgerror* as a /magic/ command name with special significance to Tcl. Callback registration is a cleaner mechanism then giving particular command names privileged status, and we should move in that direction when the opportunity arises. An alternative syntax for *interp bgerror*, *interp bgerror* /path target cmdPrefix/ was considered. This alternative would have allowed background errors in the /path/ interp to be handled in the /target/ interp. The difficulty with this alternative was in how to define the introspection form of the command. Introspection would need to return /target/ information, and it would be possible that the target interp of the handler would be an interp for which no /target/ path could be constructed to be returned (a sibling, parent, or uncle interp, etc.). The proposed form can be combined with *interp alias* to still allow background errors in one interp to (ultimately) be handled by a command evaluation in a different interp. REFERENCE IMPLEMENTATION ========================== See Tcl Patch 1060579. COMMENTS ========== Please make any comments here. COPYRIGHT =========== This document has been placed in the public domain. ------------------------------------------------------------------------- TIP AutoGenerator - written by Donal K. Fellows