TIP 755: Add a callback for post-initialization of an interpreter

Login
Author:             Ashok P. Nadkarni <[email protected]>
Tcl-Version:        9.1
State:              Final
Type:               Project
Created:            2026-05-13
Tcl-Branch:         tip-755
Forum:              8231468c85
Vote:               Done
Vote-Summary:       Accepted 6/0/0
Votes-For:          AK, AN, HO, KW, JN, MC, SL
Votes-Against:      none
Votes-Present:      none

Abstract

This TIP proposes a facility to register a callback function to be invoked after initialization of interpreters.

Rationale

The original motivation was support for loading statically linked packages in secondary interpreters (see tickets 4f06d7ca08 and 6094de399d) but is more general purpose.

In 9.0 and earlier, tclsh, wish and similar shells implemented their own Tcl_AppInit to customize the Tcl interpreter by loading static packages, adding commands, setting library paths etc.. The registry and dde packages were loaded using this mechanism in static tclsh and wish builds.

The problem, as reflected in the above bug reports, is that Tcl_AppInit is only called on the main interpreter so the customization is not present in secondary interpreters in either the same or other threads.

This TIP addresses this by providing an API to customize all interpreters after their creation.

Further, this facility is also made available to extensions as well as applications that embed Tcl but do not follow the template for tclsh.

Some possible use cases for this functionality in addition to the above:

Note that while some (not all!) of the above can be implemented already by script level customization, that needs to be done at every call site that creates interpreters which is both inconvenient (requiring potentially complex wrappers) and not always possible in case of interpreters created within extensions.

Specification

The following API is added to the core and exported via the stubs table.

typedef int Tcl_PostInitProc (Tcl_Interp *interp, void *clientData);
int	Tcl_RegisterPostInitProc(Tcl_PostInitProc *postInitProc, void *clientData);
int Tcl_UnregisterPostInitProc(Tcl_PostInitProc *postInitProc, void *clientData);
int Tcl_ClearPostInitProcs(void);

An application can call Tcl_RegisterPostInitProc to register a callback, having the Tcl_PostInitProc signature, that should be invoked after initialization (via Tcl_Init, not creation via Tcl_CreateInterp) of every subsequently created interpreter. The function returns a Tcl return code.

The callbacks are invoked at the end of any call to Tcl_Init including via the interp create command with the exception of safe interpreters.

This callback is passed the newly created interpreter and the opaque clientData value that was passed at the time of registration. It should return a Tcl return code.

Multiple callbacks are supported and will be invoked in the order of their registration except that an error return from a callback will skip the remaining registrations.

The Tcl return code from the last callback invoked is returned as the return value from Tcl_Init.

A callback may be unregistered by calling Tcl_UnregisterPostInitProc and passing it the same postInitProc and clientData values that were passed to Tcl_RegisterPostInitProc. The function returns a standard Tcl return code. It is not an error if there is no matching prior registration.

The Tcl_ClearPostInitProcs function unregisters all currently registered callbacks.

Safe interpreters

The post-initialization callbacks are not run in safe interpreters. This is a design choice to error on side of caution.

Interpreter creation in callbacks

A Tcl_Init call within a post-initialization callback will return an error. This is by design since otherwise infinite recursion will result unless the callback takes appropriate precautions.

Interpreter deletion in callbacks

Deletion of the interpreter within its initialization will documented as prohibited and an error returned if attempted. A memory leak will result but is deemed an acceptible consequence of an illegal action. See the forum thread for a sample session.

Registration changes within callbacks

The Tcl_RegisterPostInitProc and Tcl_UnregisterPostInitProc functions may be invoked from within a registered callback. However, the change in registration will not have effect for the interpreter that is being initialized.

Implementation notes

Implementation is in the Tcl tip-755 and Tk tip-755 branches.

Tcl notes

In addition to the implementation of the above functions, the following changes are made to Tcl.

Tk notes

The calls to Registry_Init and Dde_Init in static builds have been removed. These are really internal to Tcl and are no longer needed.

Testing

tcltest has been modified to make use of this functionality and load its commands in all interpreters, not just the main one. It was deemed appropriate as an application that added its own static packages. This change is not mandated for this TIP and can if reverted if deemed inappropriate.

Additionally, as a result of the above, the existing test load-5.1 has been intentionally modified. The test does an explicit load of a package into a secondary interpreter and then verifies it against info load using an exact match. Now however, because static packages are also loaded into secondary interpreter, the test has been modified to check that the package is one of the entries in the list returned by info load.

Discussion

The TIP 755 forum thread is set up for discussion of the TIP. Please submit comments there.

History

Copyright

This document has been placed in the public domain.