lshift - shift list and return first element
This is not a command included in Tcl, but rather a common 'idiom' for in place list manipulation used e.g. for implementing queues are for commandline processing.
A proper implementation should throw an error when listVar does not exist, and also when listVar contains the empty list (or string).
The following is taken from Tcl Gems though slightly modified:
proc lshift listVar { upvar 1 $listVar l set r [lindex $l 0] set l [lreplace $l [set l 0] 0] return $r }
You can use this programming idiom also without having the lshift command, e.g. with the K combinator:
K [lindex $l 0] [set l [lreplace $l [set l 0] 0]
Or more generalized:
Shift list count elements and return the respective elements.
proc lshift {listVar {count 1}} { upvar 1 $listVar l set r [lrange $l 0 [incr count -1]] set l [lreplace $l [set l 0] $count] return $r }
And finally a full fledged one with error handling:
proc lshift {listVar {count 1}} { upvar 1 $listVar l if {![info exists l]} { # make the error message show the real variable name error "can't read \"$listVar\": no such variable" } if {![llength $l]} {error Empty} set r [lrange $l 0 [incr count -1]] set l [lreplace $l [set l 0] $count] return $r }
In lshift -Adding Unique Items to Lists of Fixed Length the command lshift puts an element on a list if it is not already there. It is used to implement a 'recently used' list
In Tcl Gems lshift is used for command line arguments processing. In Stacks and Queues the genial RS names lshift 'qpop' - if push appends to the end, then pop pops from the end (stack) and lshift (qpop) pops from the front (queue).
LEG would like to contribute the following method to iterate over lines of text, whether stored in a file or in a variable:
proc vGets {listVar lineVar} { upvar 1 $listVar l $lineVar line if {[catch {lshift l} line]} {return -1} else {string length $line} } if {..} {# text in variable "text" set lines [split $text \n] set getLine vGets } else {# text in channel fd set lines $fd set getLine gets } while {[$getLine lines line]!=-1} { # do something with the line .. }