Mike
Mike

Reputation: 1319

Accessing variables in TCL across scopes

I'm trying to learn tcl scripting. My req is very simple. I need to access the array "args" in the second if condition in the for loop. I tried the code below. Since "argv" scope is limited to second if condition, it is NOT accessible in for loop

Then I tried declaring argv as global var -

array set args {}

right below the ned of first if condition. Even after declaring "args" as global array did NOT help.

How do I access the variable in the cope of second if contion, in the for loop below ?

if {$argc != 4} {
puts "Insufficient arguments"
exit 1
}

if { $::argc > 0 } {
    set i 1
    foreach arg $::argv {
        puts "argument $i is $arg"
        set args(i) arg
        incr i
        }
} else {
    puts "no command line argument passed"
}

for {set x 0} { $x<2 } {incr x} {
    puts "Arrray: [lindex $args $x]"
}

Upvotes: 0

Views: 287

Answers (2)

Andrew Cheong
Andrew Cheong

Reputation: 30293

For your original code, this is the error I get:

can't read "args": variable is array
    while executing
"lindex $args $x"
    ("for" body line 2)
    invoked from within
"for {set x 0} { $x<2 } {incr x} {
    puts "Arrray: [lindex $args $x]"
}"
    (file "main.tcl" line 20)

In Tcl, arrays are not lists. You have to write

for {set x 0} { $x<2 } {incr x} {
    puts "Arrray: $args($x)"
}

But then I get this:

can't read "args(0)": no such element in array
    while executing
"puts "Arrray: $args($x)""
    ("for" body line 2)
    invoked from within
"for {set x 0} { $x<2 } {incr x} {
    puts "Arrray: $args($x)"
}"
    (file "main.tcl" line 20)

Well there's several problems here. You're setting array elements starting with index 1 but reading them starting with index 0. So let's correct that to 0 everywhere:

    set i 0

But also you're missing some $'s in the setting of the elements:

        set args($i) $arg

That looks better. Final code:

if {$argc != 4} {
puts "Insufficient arguments"
exit 1
}

if { $::argc > 0 } {
    set i 0
    foreach arg $::argv {
        puts "argument $i is $arg"
        set args($i) $arg
        incr i
        }
} else {
    puts "no command line argument passed"
}

for {set x 0} { $x<2 } {incr x} {
    puts "Arrray: $args($x)"
}

So, scope wasn't quite the issue. You're getting there though!

Upvotes: 1

slebetman
slebetman

Reputation: 114014

Tcl does not import globals by default. You need to import your globals:

global args
set args(i) arg

Some people prefer to import globals at the top of the proc:

global args

if {$argc != 4} {
    puts "Insufficient arguments"
    exit 1
}

if { $::argc > 0 } {
    set i 1
    ....

See: https://www.tcl.tk/man/tcl8.7/TclCmd/global.htm

Alternatively, you can directly access the global namespace, in fact you're already using that syntax with ::argc:

set ::args(i) arg

Upvotes: 0

Related Questions