Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Help with Tcl_UpVar()

33 views
Skip to first unread message

Arno Puder

unread,
Jan 2, 2002, 7:48:43 PM1/2/02
to

Hi,

the Tcl command upvar allows call by reference for actual parameters, e.g.:

proc func {a} {
upvar $a aa
lappend aa d e f
}

set l {1 2 3 a b c}

func l


My question: how do you implement the same behavior in C as a
Tcl-extension? I.e., 'func' is a command that is registered with
Tcl_CreateObjCommand(). My problem is that I don't know what arguments I
need to pass to Tcl_UpVar() since there are no names for the formal
parameters.

TIA,
Arno

Don Porter

unread,
Jan 3, 2002, 1:00:37 AM1/3/02
to
Arno Puder wrote:
> the Tcl command upvar allows call by reference for actual parameters, e.g.:
>
> proc func {a} {
> upvar $a aa
> lappend aa d e f
> }
> set l {1 2 3 a b c}
> func l
>
> My question: how do you implement the same behavior in C as a
> Tcl-extension? I.e., 'func' is a command that is registered with
> Tcl_CreateObjCommand().

You probably don't have to.

[upvar] makes links between variables in different Tcl variable
contexts. Each evaluation of a [proc] in Tcl creates a new context
for the local variables of that [proc]. [upvar] lets you associate a
variable in that local context with a variable in the caller's context.

When a Tcl command registered with Tcl_Create(Obj)Command() is
evaluated, there is no creation of such a new local variable context.
Instead, any C calls that operate on variables (Tcl_SetVar(), etc.)
operate in the current context [*]. There really is no "caller"
context, because there is no [proc], so there is no new context to
push on the context stack. Just operate on the variables, and things
should act as you wish.

Of course, if you *want* a new context, you can code up your command
procedure to provide one using another set of Tcl C routines. Look
at how Tcl [proc]s do that for examples.

[*] ...by default. Of course flag values like TCL_GLOBAL_ONLY, etc.
can modify things, but the docs tell you that.

--
| Don Porter Mathematical and Computational Sciences Division |
| donald...@nist.gov Information Technology Laboratory |
| http://math.nist.gov/~DPorter/ NIST |
|______________________________________________________________________|

Arno Puder

unread,
Jan 3, 2002, 2:41:42 PM1/3/02
to d...@email.nist.gov

Don,

thanks for your reply. What you write makes sense, but I have trouble to
get it to work. When I try to modify an argument passed via Tcl_Obj*
objv[], I get the error "Tcl_ListObjAppendElement called with shared
object" (I try to append an element to a list passed as the actual
parameter).

The docs say that I need to duplicate the object before modifying it,
but this is exactly what I don't want to do for call by reference.

What now?
Arno

Don Porter

unread,
Jan 3, 2002, 3:29:03 PM1/3/02
to
Arno Puder wrote:
> When I try to modify an argument passed via Tcl_Obj*
> objv[], I get the error "Tcl_ListObjAppendElement called with shared
> object" ...

> The docs say that I need to duplicate the object before modifying it,
> but this is exactly what I don't want to do for call by reference.

Yes, in your command procedure registered with Tcl_CreateObjCommand()
you do need to respect the copy-on-write semantics of Tcl_Obj's.

See http://mini.net/tcl/1192.html for an illustrative example
that also indicates a situation where you may be able to avoid
unnecessary Tcl_DuplicateObj() calls.

Ultimately, though, if you need it, you need it.

Tom Wilkason

unread,
Jan 3, 2002, 3:52:21 PM1/3/02
to
"Arno Puder" <ar...@research.att.com> wrote in message
news:3C34B3F6...@research.att.com...

|
| Don,
|
| thanks for your reply. What you write makes sense, but I have trouble to
| get it to work. When I try to modify an argument passed via Tcl_Obj*
| objv[], I get the error "Tcl_ListObjAppendElement called with shared
| object" (I try to append an element to a list passed as the actual
| parameter).
|
| The docs say that I need to duplicate the object before modifying it,
| but this is exactly what I don't want to do for call by reference.
|
| What now?
| Arno
When you do a Tcl_DuplicateObj( listPtr ), you aren't making a duplicate of the list,
you are making a duplicte of a reference to the list (just another listPtr object).
The data contained within the list remains where it is. You don't sacrifice much in
terms of speed. Without the Tcl_DuplicateObj if you did something like:

set l {1 2 3 a b c}

set a $l # This makes a copy of the list reference (does NOT copy the list data)
func l # where you modify the contents of list l, say for example it is changed to
{3 2 1 a b c}
set l
=> 3 2 1 a b c
# Then if you did
set a
=> 3 2 1 a b c # opps, didn't really want a to change too!
#hence the Tcl_DuplicateObj


Tom Wilkason

Arno Puder

unread,
Jan 3, 2002, 4:13:14 PM1/3/02
to

Don Porter wrote:

> See http://mini.net/tcl/1192.html for an illustrative example


That is exactly what I was looking for!

Thanks a bunch,
Arno

Donal K. Fellows

unread,
Jan 9, 2002, 6:24:17 AM1/9/02
to
Tom Wilkason wrote:
> When you do a Tcl_DuplicateObj( listPtr ), you aren't making a duplicate
> of the list, you are making a duplicte of a reference to the list (just
> another listPtr object). The data contained within the list remains where
> it is.

Technically you get a copy of the list itself, and the objects contained
in the list have their reference counts incremented.

Donal.
--
Donal K. Fellows http://www.cs.man.ac.uk/~fellowsd/ fell...@cs.man.ac.uk
-- Short attention span since- ooh! Shiny thing on the floor!
-- Chad R. Orzel <orz...@earthlink.net>

0 new messages