Forum OpenACS Development: uplevel with passed variables

Collapse
Posted by Samer Abukhait on
ad_proc -public myProc {Var} {} {
        uplevel {
    Some Code Using Var
        }
}

What I am aiming at is simply a procedure that use a passed variable value and set some other variables in the caller’s environment.
Is uplevel the right choice? If yes, how I might use Var inside uplevel?

Collapse
Posted by Tom Jackson on
You can't do that. Uplevel runs the code in a different environment (usually). What you might try is upvar:

set var "test"

proc my_proc {myVar} {

  upvar $myVar myLocalVar
  puts "myVar is '$myVar' value is '$myLocalVar'"

}

set var "test"

# pass in name of var, not value of var:

my_proc "var"

# should output "myVar is 'var' value is 'test'"
Collapse
Posted by Samer Abukhait on
I came out to the following solution:

ad_proc -public myProc {Var} {} {
        upvar X_var vv_var
        set vv_var $Var
        uplevel {
          Some Code Using X_var
        }
}
I don’t know if this is the ‘most’ right solution.

Collapse
Posted by Tom Jackson on

If you run:


myProc "var"

#The result will be the same as executing:

Some Code using X_var

You can try to pass things into the uplevel, but it will never work. Your proc would have the same effect if it were written:

ad_proc -public myProc {} {} {        
    uplevel {
        Some Code Using X_var
    }
}
Collapse
Posted by Nis Jørgensen on
Samer, your example works fine with me. For instance:

ad_proc -public myProc {Var} {} {
        upvar X_var vv_var
        set vv_var $Var
        uplevel {
          set Y_var "${X_var}bar"
        }
}

myProc "foo"
set Y_var


returns "foobar" just as it should.
Collapse
Posted by Tom Jackson on

To answer your question if this is the most right solution: no it isn't. The use of uplevel/upvar is very application specific, and your example is about as far away from needing either of these features (and you use both), that you can get. If you have the actual code you want to run, then show us that so we can offer more a realistic assessment. Maybe start by reading the manual entry for uplevel/upvar.

Collapse
Posted by Tilmann Singer on
Standard disclaimer: don't use uplevel/upvar unless you exactly know why you are doing it and that it is definitely necessary, as opposed to simply passing in all variables as parameters and returning them e.g. as array list. The danger is that code becomes hard to maintain and hard to understand for outsiders when using this feature too much.
Collapse
Posted by Samer Abukhait on
Suppose that many pages are doing some processes based on 2 (or more) attributes of a passed object.

All Pages accept a parameter object_id and based on the object's attributes it processes something..

My procedure aims to check if the logged member has the right permission on the passed object and set's the object's attributes in the calling page script.

Since many pages share this concept I wanted to modularize it in a procedure.

I tried your suggestion on calling uplevel without passing object_id to the procedure and it doesn't work.

Collapse
Posted by Benjamin Bytheway on
Why cannot this be done by setting and returning an array of the attributes? The method you've currently described is really an abuse of upvar/uplevel, and should be avoided.

It creates the situation where procs are making assumptions about the callers variable space.  Relying on procs to setup variables for you creates code that is difficult to maintain.  Variables are used that pop up out of nowhere, with no indication who actually set them in the first place.

Upvar and Uplevel have been abused in this project, mainly, I think, to work around shortcomings of tcl that have since been improved/corrected in 8.x.

For proper use of Upvar and Uplevel, see Rob Mayoff's guidelines:

http://dqd.com/~mayoff/notes/tcl/upvar.html

Collapse
Posted by Andrew Piskorski on
Incidentally, there is never any good reason to abuse upvar, as using it correctly is exceedingly easy, and I would hope, usually obvious. Using uplevel well is perhaps less straightforward and thus, ugly usage more forgivable.

Rob's guidelines above are very good, thanks for that reminder.