views:

70

answers:

3

I'm using a discrete event simulator called ns-2 that was built using Tcl and C++. I was trying to write some code in TCL:

set ns [new Simulator]

set state 0

$ns at 0.0 "puts \"At 0.0 value of state is: $state\""
$ns at 1.0 "changeVal"
$ns at 2.0 "puts \"At 2.0 values of state is: $state\""

proc changeVal {} {
    global state
    global ns
    $ns at-now "set state [expr $state+1]"
    puts "Changed value of state to $state"
}

$ns run

Here's the output:

At 0.0 value of state is: 0
Changed value of state to 0
At 2.0 values of state is: 0

The value of state does not seem to change. I am not sure if I am doing something wrong in using TCL. Anyone has an idea as to what might be going wrong here?

EDIT: Thanks for the help. Actually, ns-2 is something over which I do not have much control (unless I recompile the simulator itself). I tried out the suggestions and here's the output:

for the code:

set ns [new Simulator]

set state 0

$ns at 0.0 "puts \"At 0.0 value of state is: $state\""
$ns at 1.0 "changeVal"
$ns at 9.0 "puts \"At 2.0 values of state is: $state\""

proc changeVal {} {
    global ns
    set ::state [expr {$::state+1}]
    $ns at-now "puts \"At [$ns now] changed value of state to $::state\""
}

$ns run

the output is:

At 0.0 value of state is: 0
At 1 changed value of state to 1
At 2.0 values of state is: 0

And for the code:

set ns [new Simulator]

set state 0

$ns at 0.0 "puts \"At 0.0 value of state is: $state\""
$ns at 1.0 "changeVal"
$ns at 9.0 "puts \"At 2.0 values of state is: $state\""

proc changeVal {} {
    global ns
    set ::state [expr {$::state+1}]
    $ns at 1.0 {puts "At 1.0 values of state is: $::state"}
}

$ns run

the output is:

At 0.0 value of state is: 0
At 1.0 values of state is: 1
At 2.0 values of state is: 0

Doesn't seem to work... Not sure if its a problem with ns2 or my code...

+2  A: 

Edit: now understanding the state machine

First, the quoting syntax you're using is going to get you in trouble. You should generally build up Tcl commands using list, this ensures that Tcl will not expand what you don't want it to expand.

Your at-now calls are substituting the state variable when you make the call (i.e. when the value is unchanged and 0. What you want is:

$ns at-now 0.0 {puts "At 0.0 value of state is: $::state"}
$ns at-now 2.0 {puts "At 2.0 value of state is: $::state"}

It looks like your changeVal is properly written (the first version had some of the same substitution problems), as well as the fact that you were passing in variable references that would be used locally, and therefore not setting the global state.

Solution to part of first version of question - Use global references, and quote both the [ and $ to prevent substitution at the point of the call:

$ns at-now "set ::state \[expr {\$::state + 1}\]"

or, using curly braces:

$ns at-now {set ::state [expr {$::state + 1}]}
Trey Jackson
Thanks for the answer. As ns-2 is a simulator, I'd have to recompile it to incorporate the changes you suggested. I will work on it. As for the other things, I just updated my post. Thanks for your time.
Legend
@Legend, I updated to provide a clearer answer (b/c I re-read the question more carefully). There were two problems to overcome, and I just answered the less important one. This answer should address your concerns without needing to change ns-2.
Trey Jackson
Thanks Trey... For anyone interested in knowing the right piece of code, look for my reply here.
Legend
if you are going to escape everything you might as well put it in {} instead
jk
Sure. Point taken. Thanks
Legend
+2  A: 

The problem is you're substituting the value of your variables immediately, and not at the time the code is evaluated. You need to postpone the substitution. Thus, instead of:

$ns at 2.0 "puts \"At 2.0 values of state is: $state\""

Do this:

$ns at 2.0 {puts "At 2.0 values of state is: $state"}

It's good practice to put anything more complex than a simple call of a command without substitution in a procedure when doing a call like this. Much easier to make it work right.

[EDIT]
Also, the at-now is still postponing doing its body until after the current at returns.

Donal Fellows
Thanks. Updated my post with the output. Doesn't seem to be the problem.
Legend
A: 

I am not sure why this works but it works:

set ns [new Simulator]

set state 0

proc changeVal {} {
    global ns
    incr ::state
    $ns at-now {puts "Local::At [$ns now] values of state is: $::state"}
}

$ns at 0.0 "puts \"Global::At 0.0 value of state is: $state\""
changeVal
$ns at 9.0 "puts \"Global::At 2.0 values of state is: $state\""

$ns run

Output:

Global::At 0.0 value of state is: 0
Local::At 0 values of state is: 1
Global::At 2.0 values of state is: 1

If anyone knows an explanation, that would be great.

Legend
See my answer for why it works (hint: you changed the ordering of commands, which affected what was substituted).
Trey Jackson