Prev: List to multidimensional array conversion
Next: Increasing three digit numbers in a string by one
From: Mark Morschhäuser on 12 Jun 2010 08:27 Hello, after years of using perl I rediscovered tcl. Unfortunately I found a problem with foreach-loops and want to ask if that is on purpose in tcl (as google seems not to be my friend in this case)... If you create a list, then create a foreach loop for this list and if you append entries to the list within this loop, then the loop ends after the initial number of list entries are passed and the appended entries are ignored by the foreach command, though the entries actually were appended to the list. Example: % set l {1 2} 1 2 % llength $l 2 % foreach i $l { puts $i if {$i == 2} { lappend l 3 } } 1 2 % puts $l 1 2 3 % llength $l 3 Am I doing something wrong? The documentation states "foreach - Iterate over all elements in one or more lists", but obviously it does not :-) (To circumvent this, I made a while loop with llength-check now, this works) Greetings, Mark
From: Helmut Giese on 12 Jun 2010 09:14 Hi Mark, >Hello, > >after years of using perl I rediscovered tcl. Unfortunately I found a >problem with foreach-loops and want to ask if that is on purpose in tcl (as >google seems not to be my friend in this case)... > >If you create a list, then create a foreach loop for this list and if you >append entries to the list within this loop, then the loop ends after the >initial number of list entries are passed and the appended entries are >ignored by the foreach command, though the entries actually were appended to >the list. this is by design: The list is "looked at"/evaluated once at the beginning. If foreach were to function like you thought it would need to get passed a _list variable_ - however this would preclude such nice uses like 'foreach i {1 2 3}'. >Am I doing something wrong? The documentation states "foreach - Iterate over >all elements in one or more lists", but obviously it does not :-) It does. Note that the docs state "list", not "list variable". You will want to pay attention to this distinction since some list commands expect a "list variable" (e.g. lappend) while others expect a list (like lsearch). >(To circumvent this, I made a while loop with llength-check now, this works) You mean something like this? for {set idx 0} {$idx < [llength $l]} {incr idx} { puts [lindex $l $idx] if {$idx == 1} { lappend l 3 } } HTH Helmut Giese
From: Mark Morschhäuser on 12 Jun 2010 10:41 Hello, thanks for the hint "list" vs. "list variable", after thinking about it, I got the difference there :-) > You mean something like this? > for {set idx 0} {$idx < [llength $l]} {incr idx} { > puts [lindex $l $idx] > if {$idx == 1} { > lappend l 3 > } > } yes, exactly. This works because llength is evaluated every time again and keeps track of the actual length of the list, which is what I want in this context. Greetings, Mark
From: Donal K. Fellows on 13 Jun 2010 15:28 On 12/06/2010 13:27, Mark Morschhäuser wrote: > Am I doing something wrong? The documentation states "foreach - Iterate over > all elements in one or more lists", but obviously it does not :-) As has been noted, it does because it iterates over the list *value*. Basically, [foreach] takes a snapshot (efficiently) of the list at the start of its running and iterates over that. What this means is that it is always safe to concurrently modify the list in the variables; the iteration machinery can't get confused. (Compare this with many other languages where list iteration is fraught with difficulties because of tangles due to concurrent modification.) The down-side is that you need to define what you want to happen manually when you want the iteration to see updates. This is because while it is fairly easy to guess a strategy that would cope with appends, it can be very tough in general when elements are modified or removed and it is better for you to be explicit. Donal.
|
Pages: 1 Prev: List to multidimensional array conversion Next: Increasing three digit numbers in a string by one |