Passing by reference in script?
by Jacob · in Torque Game Engine · 01/23/2005 (12:38 pm) · 13 replies
Is it possible to pass an argument into a new script function by reference?
About the author
#2
01/23/2005 (3:15 pm)
My guess is that he wants to create a function in torquescript (new since it didn't exist last week). He wants that function to be able to change the value of some of its arguments and have those changes persist after the function completes, similar to "passing by reference" in c++ (placing a & before an argument's name).
#3
Edit: I could have explained it better in the first post...I would like to pass a variable to a function, which I create in script by reference, instead of by value - just like in C++. If that's not easy to do, there are of course ways around it but if it is, it would make things simpler for me.
01/23/2005 (7:32 pm)
Exactly what Eric said :)Edit: I could have explained it better in the first post...I would like to pass a variable to a function, which I create in script by reference, instead of by value - just like in C++. If that's not easy to do, there are of course ways around it but if it is, it would make things simpler for me.
#4
Example:
01/23/2005 (10:18 pm)
This is possible, but not on simple variables. You could use a ScriptObject for this.Example:
%myVar = new ScriptObject();
%myVar.someValue = 10;
changeMyVar( %myVar );
function changeMyVar( %someVar )
{
%someVar.someValue = 5;
}This isn't at all effecient and kind of pointless though.
#5
Yes AND no.
Torque may receive paramaters by reference, such as in the function NextToken() that gets the next token from a string and store it in the second parameter that should be passed as reference. This is done by passing the variable name without % or $ ( 3DGPAI p. 706 ).
the problem is : I have NO idea of how you receive a refferenced parameter and how it's supposed to know wheter it's a global or local variable you're referencing since the indicators are suppresed in the call.
01/24/2005 (8:28 am)
@Jacob,Yes AND no.
Torque may receive paramaters by reference, such as in the function NextToken() that gets the next token from a string and store it in the second parameter that should be passed as reference. This is done by passing the variable name without % or $ ( 3DGPAI p. 706 ).
the problem is : I have NO idea of how you receive a refferenced parameter and how it's supposed to know wheter it's a global or local variable you're referencing since the indicators are suppresed in the call.
#6
...and thanks Robert!
01/24/2005 (7:23 pm)
Thanks Bruno...interesting how you saw that in 3DGPAI. I will try to look into it some more but like I said, since there are other ways to accomplish what I need, it's not that important I suppose :)...and thanks Robert!
#7
I checked the code to see how the reference thing is done :
in consoleFunctions.cc ( line 574 )
and in console.cc (line 490 )
What they do is : check if there is a variable which name is contained in token in the stack. if it exists, then the refferenced variable is local, else it's global. so it calls the appropriate Con::functions to handle it.
you could try coding :
and in the script call setReferenceVariable(%ref,%value)
01/25/2005 (8:21 am)
FYI,I checked the code to see how the reference thing is done :
in consoleFunctions.cc ( line 574 )
// set local variable if inside a function
if (gEvalState.stack.size())
Con::setLocalVariable(token,tmp);
else
Con::setVariable(token,tmp);and in console.cc (line 490 )
void setVariable(const char *name, const char *value)
{
name = prependDollar(name);
gEvalState.globalVars.setVariable(StringTable->insert(name), value);
}
void setLocalVariable(const char *name, const char *value)
{
name = prependPercent(name);
gEvalState.stack.last()->setVariable(StringTable->insert(name), value);
}What they do is : check if there is a variable which name is contained in token in the stack. if it exists, then the refferenced variable is local, else it's global. so it calls the appropriate Con::functions to handle it.
you could try coding :
ConsoleFunction(setReferenceVariable,const char *,3,3,"setReferenceVariable(var,val)")
{
argc;
const char *var = argv[1];
const char *val = argv[2];
// set local variable if inside a function
if (gEvalState.stack.size())
Con::setLocalVariable(var,val);
else
Con::setVariable(var,val);
return val;
}and in the script call setReferenceVariable(%ref,%value)
#8
01/27/2005 (5:40 pm)
That won't work, unfortunately. It might be possible to pass references to stuff in different scopes around, but it would be complicated, both to implement and to use... I say, find a workaround. :)
#9
01/27/2005 (7:11 pm)
Well, I thought it may be too much since it hasn't been implemented into Torque Script by now :) I wasn't holding my breath :) Thanks all for your effort!
#10
This is just something that caught me. The problem seems to be getting the previous stack from setLocalVariable. As it is it creates a variable on the calling function. So I need to get the previous stack space.
I tried
But it hung. Any hints on how to work with the stack ?
01/29/2005 (8:15 am)
@Ben,This is just something that caught me. The problem seems to be getting the previous stack from setLocalVariable. As it is it creates a variable on the calling function. So I need to get the previous stack space.
I tried
Vector<Dictionary *> newstack; newstack = gEvalState.stack.last(); newstack.last()->setVariable(StringTable->insert(var), val);
But it hung. Any hints on how to work with the stack ?
#11
Personally, I think that getting it working would not really be worth the effort, given you can work around fairly painlessly.
01/29/2005 (12:54 pm)
GEvalState.stack[gEvalState.stack.size() - 1] is approximately the right idiom. You also have to update the parser/lexer/compiler to support a syntax for this, as well as extend the AST to deal with it properly. And deal with cases where you pass references multiple calls deep.Personally, I think that getting it working would not really be worth the effort, given you can work around fairly painlessly.
#12
Here is the code for a working reference passing :
and here is an example of usage that seems usefull :
Nothing like a rainy saturday to put our grey cells to work :-)
01/29/2005 (3:26 pm)
Thanks Ben, but found a workaround for it :Here is the code for a working reference passing :
ConsoleFunction(setReferenceVariable,const char *,3,3,"setReferenceVariable(var,val)")
{
argc;
const char *arg = argv[1];
const char *val = argv[2];
char var[33] = ""; // dunno torque's actual limit for variable names but 32 does the trick
// set local variable if inside a function
if (gEvalState.stack.size())
{
// Since there is a stack, let's check if it's global or local
Dictionary * laststack;
const char * test;
// save the last stack entry
laststack = gEvalState.stack.last();
// Pop it
gEvalState.stack.pop_back();
dStrcpy(var,"%");
dStrcat(var,arg);
// Con::printf("testing variable %s",var);
test = gEvalState.stack.last()->getVariable(StringTable->insert(var));
if(dStrlen(test))
{
// OK, variable exist and is local
gEvalState.stack.last()->setVariable(StringTable->insert(var), val);
}
else
{
// It doesn't exist so it must be global
dStrcpy(var,"$");
dStrcat(var,arg);
Con::setVariable(var,val);
}
// anyway, we must push_back what we popped
gEvalState.stack.push_back((Dictionary *)laststack);
}
else
{
// There is no stack so this variable MUST be global
dStrcpy(var,"$");
dStrcat(var,arg);
Con::setVariable(var,val);
}
return val;
}and here is an example of usage that seems usefull :
function reftest()
{
%test = "10 20 30 40 50 60";
%posx = %posy = %posz = %rotx = %roty = %rotz = 5;
// drawback is that local variables should be initialized before usage
BurstTransform(%test,posx,posy,posz,rotx,roty,rotz);
echo( "[" @ %posx @ "] [" @ %posy @ "] [" @ %posz @ "] [" @ %rotx @ "] ["
@ %roty @ "] [" @%rotz @ "]");
}
function BurstTransform(%transform,%p1,%p2,%p3,%p4,%p5,%p6)
{
if(%p1!$="")
setReferenceVariable(%p1,getWord(%transform,0));
if(%p2!$="")
setReferenceVariable(%p2,getWord(%transform,1));
if(%p3!$="")
setReferenceVariable(%p3,getWord(%transform,2));
if(%p4!$="")
setReferenceVariable(%p4,getWord(%transform,3));
if(%p5!$="")
setReferenceVariable(%p5,getWord(%transform,4));
if(%p6!$="")
setReferenceVariable(%p6,getWord(%transform,5));
}Nothing like a rainy saturday to put our grey cells to work :-)
#13
01/29/2005 (5:40 pm)
Gah... Interesting, though.
Associate Kyle Carter