TIP 593: Efficient List Item Existence-Test-and-Take

Author:         Donal Fellows <[email protected]>
State:          Draft
Type:           Project
Vote:           Pending
Created:        31-Dec-2020
Keywords:       Tcl, lists
Tcl-Version:    8.7
Obsoleted-By:   631


This TIP proposes a command that does part (handling lists) of the more general programme proposed by TIP #513.


TIP #513 covers the general rationale for having fused operations for testing for the presence of an item and removing that item as a single operation. However, the concrete API proposed by that TIP is somewhat complex; this TIP proposes a simplified version for the list case (other TIPs will have to handle arrays and dictionaries).


The ltake command should take three or more arguments:

ltake listVarName elemVarName index ?index ...?

The listVarName argument should be the name of a variable containing a Tcl list, the elemVarName should be the name of a variable that may have an element of the list transferred into it, and the index argument (or arguments) should indicate a particular location in the list to take the element from. The result of the command is a boolean; true if the element existed (and was transferred), false otherwise. The use of multiple index arguments will be the same as in lindex and lset.

Note that if the index path leads into a non-list or off the end of a list, the command does not error (those are cases that result in a false result), but if either listVarName or elemVarName cannot be written to, the command will error. (Conceptually, listVarName will have the updated list written back to it after the extracted element is written to elemVarName; using the same variable name in both places is unlikely to be desired.)

Code that uses this command may expect that taking from the end index will be implemented in (typically) constant time, effectively acting as a kind of "lpop". Removing from other indices (especially including 0) may be slower due to the rearrangement of the list contents.


For example:

set lv {a b c d e}
while {[ltake lv ev 2]} {
    puts "TAKEN: $ev"
puts "LEFT: $lv"

will print:

LEFT: a b


This document is placed in public domain.