lshift - shift list's elements, removing the first element and returning it as the value of the function : '''lshift''' ''listVar'' 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 command line processing. A proper implementation should throw an error when listVar does not exist, and also when listVar contains the empty list (or string). ---- ** Implementations ** 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: : '''lshift''' ''listVar ?count?'' 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 } ====== ''[fredderic]'' The two versions of this command offered above return non-simple list elements differently. One returns the first item, the second returns the first portion of the list. So I'm offering up the version I wrote for my own toolkit some time ago: ====== proc lshift {args} { lassign $args listVar count upvar 1 $listVar var if { ! [info exists var] } { return -level 1 -code error \ "can't read \"$listVar\": no such variable" } switch -exact -- [llength $args] { 1 { set var [lassign $var value] } 2 { set value [lrange $var 0 $count-1] set var [lrange $var $count end] } default { return -level 1 -code error \ "wrong # args: should be \"lshift listVar ?count?\"" # error-args "lshift listVar ?count?" } } return $value } ====== The key here, is that if you don't give an item count, then it returns the first item off the list as a discrete value. If you give a count, then it returns that many items off the front as a sub-list. Therefore, '''lshift list''' performs as the '''K''' variant, while '''lshift list 1''' performs as in the second variant shown. ** Different Interpretations ** 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 ** Nifty Tricks ** 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 .. } ====== [LV] note that within [tcllib]'s [struct] module there is a "struct::list shift" command. Perhaps some of the additional functions recently written on the wiki might fit into the same module. <> Command