TIP 221: Allow Background Error Handlers to Accept Return Options

EuroTcl/OpenACS 11 - 12 JULY 2024, VIENNA
Author:         Don Porter <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        15-Sep-2004
Keywords:       bgerror,return,options
Tcl-Version:    8.5
Tcl-Ticket:     1060579


This TIP proposes a new system for registering a background error handler of an interp so that the full set of return options ([90]) can be passed to it.


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 [90] passed along to bgerror in any way.


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 ([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 ([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.


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.


Please make any comments here.


This document has been placed in the public domain.