Game Development Community

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?

#1
01/23/2005 (3:11 pm)
"new script function"?
#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
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
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
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
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
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
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
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
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.