Can I use uplevel/upvar instead of having to use global? - tcl

So, I am testing somethings out, and have a "test" proc like so:
proc test {arg} {
global state
puts "Your arg is: $arg"
set state 1
}
test somearg
vwait state
From reading about uplevel and upvar, is there a way that I can get away with not having to use global, and use either one of those options to set the state to "1" and then exit the program?

Yes, except that vwait always uses global variables for waiting on (strictly, it resolves variable names in the global scope; you can use other namespaces if you provide qualified names). What you can't do is wait on a local variable (because events can't see local variables outside their own call stack). Maybe this will change in the future, but certainly not now.
In relation to the question about global, these statements are all the same in effect inside a procedure:
global foo
variable ::foo
upvar #0 foo foo
upvar ::foo foo
namespace upvar :: foo foo
You also have a bug in your code: you set the state before waiting for it to change. That won't work anyway because you've got to wait first, and set the state from within some kind of event.

You're asking for two different things. First, about the variable. You can use upvar like so:
proc test {arg} {
upvar #0 state state
puts "Your arg is: $arg"
set state 1
}
Or, more easily, you can just use the namespace qualified name:
proc test {arg} {
puts "Your arg is: $arg"
set ::state 1
}
The second "half" of your question is some odd usage of vwait. I just want to point out that your snippet of code won't complete because you're waiting for the variable 'state' to change, but there's no event that will ever change state. You already changed it when you called test. So, unless you've set up a window/button or something that might cause state's state to change, your script will hang.
It's worth reading the wiki and the man page for vwait.

Related

How to write the equivalent tcl script for "wait until (SomeSignal)" in ModelSim

I am writing tcl scripts as a wrapper for my VHDL simulation and I am trying to implement the equivalent of the following VHDL pseudo code snippet:
Data <= SomeData;
wait until (strobe = '1');
Data <= NewData;
I tried to do that by creating a loop in tcl that checks the value of the strobe signal for some amount of time but it is extremely inefficient. As far as I see "when" clause is not going to help as well. Are there any suggestions?
proc wait_until {sig val} {
for {set i 0} {$i < 50} {incr i} {
set dummy [examine -radix unsigned $sig]
if {$dummy eq $val} {
break
}
run 10 ns
}
}
you run it:
wait_until strobe 1
Short answer: vwait does "wait until variable is written to (by some event callback)", and that's when you reevaluate the expression to see if it has changed, going back to waiting if it hasn't. The variable name given to vwait must be a global variable (or the qualified name of a namespace variable); it cannot be a local variable.
Longer answer: You can use a variable trace to determine whether to reevaluate the expression, and then write (an arbitrary value) to some sort of trigger variable that vwait notices. The trigger variable has to be global, but the trace can be on a local variable if needed. (You formally take a performance hit for that, but it doesn't matter if that's what you need.)
However, in all cases you'll need some sort of event (or rather a callback in response to an event) somewhere that causes the variable in the expression to change.

Use of "trace add variable read" in tcl

New to tcl and trying to understand the "trace add variable" command.
I understand the need to invoke a callback function when a variable is "written" to.
But what is the use of the "read" option? For debugging?
One example use might be a global counter:
proc init { } {
set ::globalcounter 0
trace add variable ::globalcounter read ::gcountUpdate
}
proc gcountUpdate { } {
incr ::globalcounter
}
proc main { } {
init
puts $::globalcounter
puts $::globalcounter
}
main
I'm sure there are other uses. As you pointed out, debugging.
It could be used for enforcement of variable access by specific procedures.
One of the uses for read callbacks (which are indeed quite a bit less common than write callbacks) is in linking a Tcl variable to a C variable; the read callback is used to enforce the reading of the C variable and synchronizing the Tcl variable to it. (The write callback would ensure that the update of the Tcl variable gets reflected to the C variable.) Tcl's got a built-in C API that uses this mechanism, though it's using the underlying C API for variable traces rather than the Tcl API that is built on top of it.
You could also use a read callback to make an apparently read-only variable:
trace add variable foo read {apply {args {
upvar "#0" foo v
set v "definitely this"
}}}
puts $foo
set foo "that"
puts $foo
I don't recommend using variable traces on local variables. They have a lot more overhead (and internal complexity) than for global/namespace variables.

What is the difference between a TCL namespace and a stack frame?

Upvar creates a link to a variable in a different stack frame, sometimes called a call stack, or a different scope.
Upvar is also used to create an alias for a global (or namespace) variable 2. But a namespace is created only by the namespace eval command. A new stack frame is created by the proc command.
Namespace and call stacks appear to be two ways that the TCL naming context can change. Upvar and Uplevel can work on both namespaces and call stacks.
Did I get it right? I have yet to see a direct comparison between call stacks and namespaces, hence my question.
No, not quite. Namespaces and call frames are very different concepts. A namespace is a hierarchical structure of names that can disambiguate synonyms. You might have three variables named foo in your program, but they won't clash if you put them in different namespaces. Namespaces can be used both for variable and command names. Once created with namespace eval a namespace's contents are always accessible until you call namespace delete on it.
A call stack is a sequence of stack frames. The first stack frame, #0, always exists. Other stack frames are created whenever a command is called (this goes mostly for commands that are user-defined procedures, the "built-in" commands follow their own rules). They are destroyed again when the command returns. So if you call command A, and A calls command B, and B calls command C, you have a call stack that looks like this:
#3 : <C's variables>
#2 : <B's variables>
#1 : <A's variables>
#0 : <global and namespace variables>
Each stack frame is a scope in the sense that only the variables that are created there or imported into it can be accessed, unless you use upvar. Everything else is hidden. In most programming languages, names from an outside scope, such as the global scope, can be automatically accessed from an inner scope. Not so in Tcl.
Using upvar you can let a command look at things outside its own stack frame. C could, for instance, use upvar #0 foo bar to create an alias (bar) for the global variable foo, or use upvar 1 baz qux (note without a #) to create an alias (qux) for the variable baz in B's stack frame.
The uplevel command can be used along the same lines to execute a script in another stack frame, including the global one. During the execution, the script can access everything that is in that stack frame, but nothing else, including the variables in the stack frame that uplevel was called from.
C can also create an alias for the namespace variable ::abc::def using upvar #0 ::abc::def ghi, but don't do that, use namespace upvar ::abc def ghi instead.
Instead of upvar #0 foo foo you can use global foo to import a global variable. Inside a command defined in a namespace, the variable command can import variables defined in the same namespace.
It is often useful to upvar or uplevel into #0 (the global frame) or 1 (the caller's frame). Using other frame numbers is error-prone and usually an indication of poor design. The invocation upvar 0 foo bar creates an alias (bar) for a variable (foo) in the same stack frame, which can be surprisingly useful.
Commands that are called by events being processed execute outside the call stack, using the global level. There is no way for them to reach inside the active stack frames and access variables that reside there.
A simple demonstration:
namespace eval ::abc {
variable def 42
proc xyz {} {
variable def
}
}
set foo 1138
proc A {} {
B
}
proc B {} {
set baz 1337
C
}
proc C {} {
upvar #0 foo bar
puts $bar
upvar 1 baz qux
puts $qux
namespace upvar ::abc def ghi
puts $ghi
}

Manipulation of variables inside a proc with bind

Sorry for the title couldn't think of anything better.
Heres my question:
Im trying to change a variable inside a proc only when the user hits space. the proc loops itself with after so if the user wish to hit space more then once the variable will increment.
Heres what I know:
There are many ways to go about this. You can pass variable inside the proc, you can link the variable with global or upvar and/or if your in a namespace then you can use variable. but the only one that seem to work with my is global. I'm getting a feeling it's because global makes a link but if thats true then variable should work too, right?
Here my test code:
proc test1 {} {
global testing
bind . <Key-a> {incr testing}
puts $testing
puts "test2"
after 100 test2
}
namespace eval test2 {
variable testing 0
namespace export {[a-z]*}
proc of1 {} {
variable testing
bind . <Key-a> {incr testing}
puts $testing
after 100 test3::of1
}
}
proc test3 {testing} {
bind . <Key-a> {incr testing}
puts $testing
puts "test4"
after 100 test4 $testing
}
set testing 0
#test1
test2::of1
#test3 0
grid .c
side question:
Why is it that in the global namespace we use set and global while in namespace we use variable (that seem to set and do global in one command). they seem to do the same job in different namespaces?
Variables in Callbacks
The scripts registered by the bind command — also in things like after events and fileevent callbacks — are evaluated in the global scope because they may be called long after the procedure that defined them returns; Tcl does not do scope capture (and that's actually a really complicated feature, so it isn't likely to come soon unless someone writes lots of code). This means that the variable that you want your procedure to notice changes to must also have global scope.
However, namespaced variables count just fine as global variables for the purpose of this discussion as they're nameable from a global context (real local variables are not). That means that we can do several ways to build a script that accesses a namespace variable from a bind-defined callback. Here's one of the nicer ones:
bind . <Key-a> [namespace code {incr testing}]
That's effectively the same as this:
bind . <Key-a> [list namespace eval [namespace current] {incr testing}]
(There are some strict differences that don't matter in this example.)
Another way to do the callback is this:
bind . <Key-a> [list incr [namespace which -variable testing]]
Which in this case is going to be much like:
bind . <Key-a> [list incr [namespace current]::testing]
If things are getting any more complicated than this toy example, it's time to stop updating variables directly in a binding script and instead write a helper procedure. That always simplifies things a lot. Or to use a class/object to encapsulate the details.
The variable Command: Why and Where to Use It
Why is it that in the global namespace we use set and global while in namespace we use variable (that seem to set and do global in one command). they seem to do the same job in different namespaces?
That's a good question. In fact, what global does is very much like upvar #0 (with the variable names doubled up), and set is a fundamental variable access command. They're commands that you can use regularly wherever you want their behaviour.
The variable command is rather stranger. What it does is three-fold:
If called in a namespace context and the variable does not exist in that namespace, it creates that variable in a present-but-unset state.
If called in a context with local variables, it links a local variable with the name (after stripping everything up to the last namespace separator) to a namespace variable with the name (using the whole supplied name if there are qualifiers, and resolving non-absolute names with respect to the current context namespace). This also forces the namespace variable to exist in the present-but-unset state.
If a value is given, the namespace variable is set to the value. This gets rid of the present-but-unset-ness.
The important behaviour is actually the creating of that present-but-unset state, since otherwise you can end up with a set (or array set) in the namespace escaping that namespace and instead working with a global variable, but not always. It all depends on the exact behaviour of the code that resolves variables, and that's deeply tricky. This is hard to explain properly, and ridiculously hard to justify. It's been the cause of quite a few outright bugs, and is definitely no better than a horrible misfeature.
The setting of the initial value is little more than a lollipop; you could instead put set straight afterwards without ill-effect. What's more, it inhibits using variable to pull in multiple variables from a namespace except in the case where you're setting them to a known value; great for initialisation, but sucky for other uses. (In case you hadn't guessed, I think this is an area of Tcl where the interface was got rather badly wrong back when it was introduced, back in Tcl 8.0. Not one bit of this is nice.)
The key take-away is this though:
Always use variable in your namespaces to declare variables as this is the only way you can be sure that the semantics is predictable. You can then initialise them any way you want. (You have to do it this way if you're creating arrays.)
Fully-qualified variable names have no craziness associated with them. Tcl always knows exactly how to look up the thing you're naming in that case.

tcl namespace error

I have several functions defined in namespace "b" which I export. I then import these functions to namespace ::x::Y, thusly:
namespace eval ::x::y "namespace import fun"
some time later I do:
namespace eval ::x::y fun
Where fun does:
proc fun {} {
puts "[namespace current]"
uplevel {puts "[namespace current]"}
}
What is printed is:
::b
::x::y
What I want and need is for 'fun' to happen in ::x::y and not in ::b. What am I doing wrong?
That's not how Tcl's namespaces work. Each procedure is associated with exactly one namespace, which is the one in which its name is located. When you use namespace import, an alias to the procedure is placed in the importing namespace that allows the procedure to be invoked from that other namespace, but the procedure itself remains in its original namespace and executes in that one.
If you want to know the caller's namespace, use uplevel namespace current (or uplevel 1 {namespace current} for a slightly windier but more efficient version). This doesn't actually tell you what namespace contained the command that was used to invoke the procedure though; for that, you need this monstrosity (in the invoked command):
namespace qualifiers [uplevel 1 [list namespace which [lindex [info level 0] 0]]]
Of course, if you're needing that a lot then you're probably doing something wrong. (That's obvious, given the length and complexity of code required to get the information.)
In particular, if you're pretending to do object orientation with this, please stop and use a real object system that gets all the tricky details right. Tcl 8.6.0 includes one (two, if you've got the contributed extensions), and there are many for older versions available as extension packages.