TIP 498: Simplify Tcl_DeleteNamespace

Login
FlightAware bounty program for improvements to Tcl and certain Tcl packages.
Author:         Nathan Coulter <tcltips@pooryorick.com>
State:          Draft
Type:           Project
Vote:           Pending
Created:        18-Jan-2016
Post-History:
Keywords:       tcl
Tcl-Version:    8.7

Abstract

Simplify the implementation of Tcl_DeleteNamespace in order to make behaviour more consistent, facilitate the resolution of outstanding issues, and pave the way for further developments.

Rationale

Tcl_DeleteNamespace plays a key role in the deallocation of various resources, from interpreters to objects in object systems, but the current implementation is problematic. Troubling indicators include:

The accumulation of the flags NS_DYING, NS_DEAD, and NS_KILLED, some of which were added to fix things up when trouble arose, and indicate subtly different states during cleanup.

Namespace.earlyDeleteProc was added in order to make namespaces usable by TclOO and other object systems, but if the order of cleanup operations had been different, it wouldn't have been necessary.

DeleteInterpProc calls TclTeardownNamespace and then later calls Tcl_DeleteNamespace, which also calls TclTeardownNamespace. This currently "works", but it's difficult to reason about interpreter cleanup and what latent bugs might exist. It's likely that there are some.

After a namespace is deleted, any evaluation levels using it as the current namespace still have access to it, and commands and variables can still be created in it but they disappear at some later point depending on the state of the call stack. Although this behaviour is documented, it was probably a concession to the implementation rather than by original intent. A further complication is that it's possible to simultaneously access both the deleted namespace and a new namespace having the same name. Reports that illustrate these issues include:

A namespace loses track of itself

command found in deleted namespace

namespace deletion: trace that calls [apply], specifying the namespace, doesn't fire.

Finally, the current cleanup routines perform enough contortions to be a real barrier to any further improvement of the system.

The work to simplify the TclOO implementation, lead to the work to simplify Tcl_DeleteNamespace.

There are various reports about traces that that silently fail under one condtition or another. The simplification of Tcl_DeleteNamespace is a precursor to the resolution of those issues.

Proposal

The implementation of Tcl_DeleteNamespace will by simplified by reordering its cleanup operations and tidying up related code. When a namespace is deleted, any evaluation levels using that namespace as the current namespace will instead use the global namespace. While this behaviour might be surprising to the user, the current situation, where phantom namespaces disappear at the will of the interpreter, is even more surprising. It is easier to discover that the current namespace is the global namespace than it is to determine why a namespace which exists at one point no longer exists at another point, even though there is no point in between at which the namespace is deleted.

The completion of this TIP will render more tractable the issue trace deletes the namespace when a command is replaced, producing "called Tcl_CreateHashEntry on deleted table".

activationCount is removed from the Namespace structure, slightly reducing is size. See also, Improve average size of Namespace.

NS_KILLED will no longer be needed. A namespace being deleted is either NS_DYING while deallocation of related resources is in progress or NS_DEAD while it's still referenced somewhere.

The issue (tailcall|yieldto) failed to find the proper namespace Abort becomes more straightforward to reason about since there are no longer namespaces that exist but that are not reachable by name.

It will be documented that when a namespace is deleted, ensemble commands, child namespaces, commands in the namespace, and variables in the namespace are deleted in that order. Because the deletion of a resource can trigger the creation of other resources, this process iterates until all relevant resources are deleted. It is left to the programmer to ensure that an loop does not occur. Currently variables are deleted before commands, but variables are more fundamental in the sense that commands can reference them, and it is reasonable to tear down the structure before removing the foundation.

Implementation

See the bug-e593adf103-core-8 branch.

Copyright

This document has been placed in the public domain.