Q:

tcl switching namespaces and proc arguments

I have a little problem which I cannot explain at the moment. I created a minimalistic code snippet to show my problem or lack of understanding how tcl namespaces are working.
So I have the file test.tcl:
namespace eval test {
    proc print {file_name} {
        namespace inscope ::test2 {
            printFileName $::test::file_name
        }
    }
}

namespace eval test2 {
    proc printFileName {file_name} {
        puts $file_name
    }
}

Than I use tclsh and run:
source test.tcl
test::print test.dat

Which returns:
can't read "::test::file_name": no such variable

Why is that should the argument of test::print not be in the ::test namescope?
I have an easy workaround with set ::test::filename $filename before namespace inscope {}.
But I am not satisfied since I miss something here.
I cannot just run ::test2::printFileName $file_name since my real world code is more complex and does not run just one command it sources a list of commands which are all in a different namespace.

A:

Local variables are not namespace variables. In particular, even with variable linking (the mechanism underlying upvar and global and variable etc.) formal parameter variables are never namespace variables in any way. That's just how the variables are mapped, because it's very fast to do; the procedure entry code is one of the hottest parts of Tcl's implementation code, so great efforts are taken to keep it as fast as possible.
But all is not lost!
You can copy the value to a namespace variable easily enough, or even do tricks with traces and upvar to make it appear like the local variable can be written back to from that interior scope. (You'll probably have to use info level to search back up the stack for where to inject the write, which will be horribly messy, but it will work.)
But what I'd instead do is make commands to provide the values (and possibly allow writing back as necessary). I think it's a bit cleaner.
namespace eval test {
    proc print {file_name} {
        proc ::test2::file_name {} [list return $file_name]
        namespace eval ::test2 {
            printFileName [file_name]
        }
    }
}

namespace eval test2 {
    proc printFileName {file_name} {
        puts $file_name
    }
}

You can make this more elegant through the use of namespace path so that you don't have to build a whole new procedure each time you call. interp alias can help too (it's a good way to do argument currying, if you're familiar with that sort of thing from functional programming).

