Ticket UUID: | 3588176 | |||
Title: | variable already exists (variable is a filesystem path) | |||
Type: | Bug | Version: | None | |
Submitter: | pooryorick | Created on: | 2012-11-17 15:59:04 | |
Subsystem: | 07. Variables | Assigned To: | dgp | |
Priority: | 5 Medium | Severity: | ||
Status: | Closed | Last Modified: | 2012-11-18 03:53:54 | |
Resolution: | Invalid | Closed By: | pooryorick | |
Closed on: | 2012-11-17 17:07:17 | |||
Description: |
The script below produces the following error: variable "item" already exists while executing "variable item tmpa/a/one" ("uplevel" body line 1) invoked from within "uplevel [list variable $varname $val]" (procedure "for" line 34) ... The script is a little verbose, but it's the most whittled-down excerpt which still produces the error: #! /bin/env tclsh if {[namespace which [namespace current]::for_global] eq {}} { rename ::for for_global if {[namespace current] ne "::"} { interp alias {} ::for {} [namespace current]::for } } proc for args { if {[lindex $args 1] eq "in"} { if {[llength $args] % 3 != 1} { return -code error "wrong # of arguments" } set iters [dict create] set vars [dict create] while {[llength $args] > 1} { set args [lassign $args[unset args] varnames /dev/null iter] if {$iter ne {} && [uplevel [::list namespace which $iter]] eq {}} { return -code error "no such iterator: $iter. Maybe \[foreach] was intended?" } dict set iters $iter 1 dict set vars $varnames $iter } set body [lindex $args[set args {}] 0] while {[dict size $iters]} { set newvals[set newvals {}] [dict create] dict for {varnames iter} $vars { foreach varname $varnames { if {[namespace which $iter] eq {}} { dict set newvals $varname {} } else { dict set newvals $varname [uplevel [list $iter]] if {[namespace which $iter] eq {}} { dict unset iters $iter dict set newvals $varname {} } } } } if {[dict size $iters]} { dict for {varname val} $newvals { uplevel [list variable $varname $val] } set code [catch {uplevel $body} result] switch -exact -- $code { 0 {} 1 { return -errorcode $::errorCode -code error $result } 3 { # FRINK: nocheck return } 4 {} default { return -code $code $result } } } else { break } } } else { uplevel [list [namespace current]::for_global {*}$args] } } proc iterdir {path} { variable uniqueid set subdirs [list $path] coroutine [incr uniqueid] apply { path { set yield [yield [info coroutine]] foreach item [glob -nocomplain -directory $path *] { if {[file isdirectory $item]} { for item in [iterdir $item] { yield $item } } else { yield $item } } }} $path } variable uniqueid 0 set tempdir [file mkdir zook1] file mkdir [set tmpa [file join $tempdir tmpa]] set res [list] for item in [iterdir $tempdir] { lappend res [string range $item [string length $tempdir] end] } puts $res | |||
User Comments: |
pooryorick added on 2012-11-18 00:07:17:
allow_comments - 1 as explained by ferrieux ferrieux added on 2012-11-17 23:12:25: Here's a much smaller case: % proc f {} {set item 1;g} % proc g {} {uplevel {variable item 2}} % f variable "item" already exists It is collision between a local and an attempt to define a new namespace variable with the same name. You can even trigger it without uplevelling: % proc h {} {set item 1;variable item 2} % h variable "item" already exists I dunno whether Tcl should be blamed for that. As a programmer, I can't imagine a case where this wouldn't actually detect a PBKAC ;) pooryorick added on 2012-11-17 23:02:15: pasted code got indentation stripped, so attaching file as well pooryorick added on 2012-11-17 23:01:37: File Added - 456677: tmp1 |
Attachments:
- tmp1 [download] added by pooryorick on 2012-11-17 23:01:37. [details]