333.md at [d81fa93cda]

Login

File tip/333.md artifact 782f127771 part of check-in d81fa93cda


# TIP 333: New Variable and Namespace Resolving Interface
	Author:         Arnulf Wiedemann <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        13-Oct-2008
	Post-History:   
	Keywords:       Tcl,resolution
	Tcl-Version:    9.1
-----

# Abstract

This is a TIP to allow easy command and variable resolving for itcl-ng, but is
not restricted to itcl-ng. It should be possible for an application to drive
the rules for command and variable lookup using the interface described
below. This TIP should allow to get rid of namespace and interpreter resolvers
for itcl-ng.

# Rationale

The current implementation for command and variable resolution using namespace
and interpreter resolvers has a lot of problems for the Tcl core
implementation. Second problem is the additonal performance penality for using
the resolvers \(much more code is needed in the application\). The suggested
interface allows to hide Tcl core details concerning handling of variables and
commands from the outside. If the interface would be made public, it would be
also possible to avoid use of tclInt.h in that area and to only use stubs
interfaces, which means itcl-ng versions would be independent of Tcl versions.
Other applications \(e.g. snit\) could also use this interface for fast lookup
of variables and commands.

# C-API Specification

At the moment there is only a need for a C-API for the suggested functionality

## For Commands \(methods/procs\)

 > typedef int \(\***TclCheckClassProtectionProc**\)\(Tcl\_Interp \*_interp_,
   Tcl\_Namespace \*_nsPtr_, const char \*_varName_, ClientData
   _clientData_\);

 > typedef void \(\***Tcl\_ClassCommandDeleteProc**\)\(ClientData
   _clientData_\);

 > typedef void \(\***Tcl\_ObjectCommandDeleteProc**\)\(ClientData
   _clientData_\);

 > ClientData **Tcl\_RegisterClassMethod**\(Tcl\_Interp \*_interp_,
   Tcl\_Namespace \*_nsPtr_, const char \*_cmdName_, ClientData
   _clientData_\);

 > Tcl\_Command **Tcl\_RegisterObjectMethod**\(TclInterp \*_interp_,
   ClientData _objectPtr_, const char \*_cmdName_, Tcl\_Command _cmdPtr_,
   ClientData _clientData_\);

 > void **Tcl\_UnregisterClassCommand**\(Tcl\_Interp \*_interp_, Tcl\_Namespace
   *_nsPtr_, const char \*_cmdName_, Tcl\_ClassCommandDeleteProc
   _delProc_\);

	 > void **Tcl\_UnregisterObjectCommand**\(Tcl\_Interp \*_interp_, ClientData
   _objectPtr_, const char \*_cmdName_, Tcl\_ObjectCommandDeleteProc
   _delProc_\);

	 > int **Tcl\_SetCallFrameObject**\(Tcl\_Interp \*_interp_, ClientData
   _objectPtr_\);

	 > int **Tcl\_SetNamespaceCommandProtectionCallback**\(Tcl\_Interp \*_interp_,
   Tcl\_Namespace \*_nsPtr_, TclCheckNamespaceProtection _cnpProc_\);

## For Variables \(variables/commons\)

 > typedef int \(\***TclCheckClassProtection**\)\(Tcl\_Interp \*_interp_,
   Tcl\_Namespace \*_nsPtr_, const char \*_varName_, ClientData
   _clientData_\);

 > typedef void \(\***Tcl\_ObjectVariableDeleteProc**\)\(ClientData
   _clientData_\);

 > typedef void \(\***Tcl\_ClassVariableDeleteProc**\)\(ClientData
   _clientData_\);

 > ClientData **Tcl\_RegisterClassVariable**\(Tcl\_Interp \*_interp_,
   Tcl\_Namespace \*_nsPtr_, const char \*_varName_, ClientData
   _clientData_\);

 > Tcl\_Var **Tcl\_RegisterObjectVariable**\(TclInterp \*_interp_, ClientData
   _objectPtr_, const char \*_varName_, ClientData _clientData_, Tcl\_Var
   _varPtr_\);

 > void **Tcl\_UnregisterClassVariable**\(Tcl\_Interp \*_interp_,
   Tcl\_Namespace \*_nsPtr_, const char \*_varName_,
   Tcl\_ClassVariableDeleteProc _delProc_\);

 > void **Tcl\_UnregisterObjectVariable**\(Tcl\_Interp \*_interp_, ClientData
   _objectPtr_, const char \*_varName_, Tcl\_ObjectVariableDeleteProc
   _delProc_\);

 > int **Tcl\_SetCallFrameObject**\(Tcl\_Interp \*_interp_, ClientData
   _objectPtr_\);

 > int **Tcl\_SetNamespaceVariableProtectionCallback**\(Tcl\_Interp
   *_interp_, Tcl\_Namespace \*_nsPtr_, TclCheckNamespaceProtection
   _cnpProc_\);

# Detailed Description

For details on how itcl-ng is using variables scopes and command scopes look
here: <http://wiki.tcl.tk/21676>

I am only describing details for variables, as variables are more complex and
commands are handled very similar to variables in itcl-ng concerning lookup.
There is the need for collecting all variables from an itcl-ng class hierarchy
for every class in the hierarchy together with the class \(which is a
namespace\). Then for each such collection there is the need to specify which
variables are used phisically based on a per object basis, because every
object has an own set of variables for the class hierarchy tied to the object.
There is the need to switch these variable collections during runtime for
every itcl-ng method \(a method is similar to a tcl proc\) which is called.
Every method is called in the class \(namespace\) where it is defined. Therefor
it is necessary to have a registration mechanism for variables on a class and
object base. During execution when calling a method the appropriate set of
object variables for the currently active object has to be available on a per
CallFrame basis \(Tcl\_SetCallFrameObject\).

The protection check function shall be called when a class variable is found
to check the protection level by the caller according to the protection rules
for the application. The clientData structure has to be filled by the
application with the appropriate data when registering a variable.

The suggested rules for lookup should be: on all places where the namespace
resolvers are called at the moment to additionally \(instead of\) do the lookup
for the new interfaces and if there is nothing found continue with normal
lookup.

The \*Unregister\* functions are for cleaning up variable information when no
longer needed. The application has to do the calls and the deleteProc is used
for freeing the contents of the clientData containers used when registering
the variables. If no registered variable for a class or object is left, also
the data structures in Tcl core used for registering and lookup should be
freed.

For commands substitute variable by command in the last few sections.

The names for the interface functions are just a suggestion, maybe someone
finds better names.

# Reference Implementation

A reference implementaion has been done for itcl-ng using the namespace
resolvers and in the resolver functions using the described interfaces. It
runs aganist the test suite without problems.

# Details about the Reference Implementation

I have used a straight forward approach, which was easy to implement.

All lookup info is at the moment in a structure available with Tcl\_SetAssocData/Tcl\_GetAssocData

Tcl\_RegisterClassVariable fills a Tcl\_HashTable with the namespace as the key \(not necessary in Tcl core there the info should be tied to the Namespace structure\). The value is a Tcl\_HashTable for the variable infos. In that hash table there are entries with varName as a key and clientData as the value.

Tcl\_RegisterObjectVariable fills a Tcl\_HashTable with the objectClientData as key and value is a Tcl\_HashTable. The key for the hash table is clientData tied to a varName from Tcl\_RegisterClassVariable and if varPtr != NULL then it is the value for the hash table otherwise a new variable is created and used for the varPtr. The variable is created at the moment in a special per object namespace but better should be stored in a per object TclVarHashTable.

Lookup in the namespace resolvers fetches the lookup data structure, looks with namespace and varName for clientData, and if found calls Tcl\_CheckClassProtection and if TCL\_OK is returned gets the itcl object and looks for the varPtr with objectClientData and clientData and if successful returns varPtr.

# Copyright

This document has been placed in the public domain.