TIP 196: Tcl Commands as Values

Login
Bounty program for improvements to Tcl and certain Tcl packages.
Author:		Robert Suetterlin <robert@mpe.mpg.de>
State:		Withdrawn
Type:		Project
Tcl-Version:	8.5
Vote:		Pending
Created:	11-May-2004
Post-History:	

Abstract

This TIP proposes making command procedures first-class values in Tcl. It also changes the command binding scheme to recognize these values before performing old-style name lookup indirection.

Rationale

A Tcl script is a string containing one or more commands separated by semicolons or newlines. The evaluation of the script breaks these commands into words. Currently the string value of the first such word is used to lookup a command procedure (effectively a function pointer) and some clientData (per-command instance state). These will then be used by the virtual machine.

For example, in the case of pure Tcl procedures created with proc command, this is TclProcInterpProc with an associated procPtr that basically references the procedure body (as a string) and its formal argument list.

Because of the name lookup indirection, Tcl does not support anonymous commands. (There is quite some interest in using such with Tcl, please compare [187] and [194]. Several other languages (even C) support anonymous commands. They seem to be quite useful, just compare their use in Tcl's C code.)

This can be changed by allowing for a new kind of word (i.e. a new Tcl_Obj commandObject) that can be immediately interpreted as a command. ([187] proposes the use of special Tcl lists, but this is too limiting for the scope of this document.) The evaluation checks if the first word is a commandObject, if not it does the old style name lookup (with unknown fallback).

A commandObject should store information equivalent to what is provided with the Tcl_CreateCommand() API and stored in the global name lookup table. Thus it can reference any command procedure and any clientData, allowing the creation of arbitrary anonymous commands in C extensions for example.

Having such commandObjects available will allow for proc to return these instead of an empty string and to skip registration of a command when its name is provided as the empty string.

Examples

This will allow to reproduce all of the features of [187]. Compare this example with the one in [187]:

proc filter {list proc} {
    set res {}
    foreach e $list {
        if {![$proc $e]} {
            lappend res $e
        }
    }
}

set a [list 1 10 100 4 5]
set b [filter $a [proc x {expr $x<10}]]

This sets the variable b to the list {10 100}.

In addition this TIP still allows:

proc {list lambda x {body}} {var} {puts $var} 

if we really want to.

And we can use commandObjects that have not been created by proc in the first place - think OOP for example.

These commandObjects could also be used as data structure for the command namespace, which would then become a dictionary, if I recall correctly. Allowing for registering an anonymous command with a name (via rename) by putting the name and the commandObject into the dictionary.

Specification

This document proposes at least the following changes to the Tcl core:

  1. Include a new Tcl_Obj commandObj that contains information equivalent to the arguments proc, clientData and deleteProc to Tcl_CreateObjCommand(). (Maybe interp is necessary, too. But I don't understand the byte compiler and execute stuff good enough to judge.)

  2. Change Tcl_GetCommandFromObj() to check if objPtr references a commandObj first, otherwise check if it finds a named command.

  3. Have the proc command return a commandObj that is equivalent to the Tcl_Create(Obj)Command() calls in Tcl_ProcObjCmd(). i.e. the proc is equal to Tcl(Obj)InterpProc() and the clientData is the procPtr.

Copyright

This document is in the public domain.

History