RETURN console function fails
by Patrick Shaw · in Torque Game Builder · 04/07/2008 (6:36 am) · 8 replies
Bug. Using the RETURN function always returns null data when calling functions from behaviors.
Repro:
I have two objects in my scene that use behaviors to communicate between objects. Originally, I did this likethis:
This works fine for me. However, I would like to use functions instead of accessing variables directly to make my code more flexible:
This set up works fine if the behaviors are on the same object. However, if get / set functions are on different objects, then "get" always returns null.
Here are two behaviors that illustrate this bug - assign them to two text objects in your scene.
Repro:
I have two objects in my scene that use behaviors to communicate between objects. Originally, I did this likethis:
%this.receiver.data = %this.sender.data;
This works fine for me. However, I would like to use functions instead of accessing variables directly to make my code more flexible:
%this.receiver.setData(%this.sender.data.getData());
function SendBehavior::getData(%this)
{
return %this.sender.data;
}This set up works fine if the behaviors are on the same object. However, if get / set functions are on different objects, then "get" always returns null.
Here are two behaviors that illustrate this bug - assign them to two text objects in your scene.
if (!isObject(GetDataBehavior))
{
%template = new BehaviorTemplate(GetDataBehavior);
%template.friendlyName = "Get";
%template.behaviorType = "Test";
%template.description = "Gets data from another object";
%template.addBehaviorField(sendDataObject, "The object to get data from", object, "", t2dSceneObject);
}
function GetDataBehavior::onAddToScene(%this, %scenegraph)
{
%this.owner.enableUpdateCallback();
}
function GetDataBehavior::onUpdate(%this)
{
%txt = %this.sendDataObject.getData();
if(%txt $= "")
%txt = "no";
%this.owner.Text = %txt;
}
if (!isObject(SendDataBehavior))
{
%template = new BehaviorTemplate(SendDataBehavior);
%template.friendlyName = "Send";
%template.behaviorType = "Test";
%template.description = "Sends data to another object";
}
function SendDataBehavior::onAddToScene(%this, %scenegraph)
{
%this.setData("Yes");
}
function SendDataBehavior::getData(%this)
{
return %this.text;
}
function SendDataBehavior::setData(%this, %data)
{
%this.text = %data;
}About the author
#2
04/07/2008 (12:42 pm)
It sounds to me as if the "sendDataObject" field isn't referencing the behavior SendDataBehavior of the second object.
#3
My naming is confusing partially because of some my recent experience with another scripting language that relies on passing messages between objects. I am "getting" the data from the "sender". Confusing, but it does work as intended. My original game script more logically named!
@Phillip/Orion,
I did some more investigation by stepping through the script in Codeweaver:
* getData is run regardless of whether its run on the object or its behavior. I verified this by placing an echo statement in the getdata function and also tracing it in Codeweaver.
* if getData is run on the behavior, it returns the proper value.
* if getData is run on an object, it returns NULL.
So, I would restate the bug as
A function defined by a behavior can be run by referencing its owner
%this.object.foo();
or the behavior's instance:
%this.object.behaviorInstance.foo();
However, when the function is called from the object, it always returns NULL. Referencing the behavior works as intended.
04/08/2008 (5:59 am)
@Orion,My naming is confusing partially because of some my recent experience with another scripting language that relies on passing messages between objects. I am "getting" the data from the "sender". Confusing, but it does work as intended. My original game script more logically named!
@Phillip/Orion,
I did some more investigation by stepping through the script in Codeweaver:
* getData is run regardless of whether its run on the object or its behavior. I verified this by placing an echo statement in the getdata function and also tracing it in Codeweaver.
* if getData is run on the behavior, it returns the proper value.
* if getData is run on an object, it returns NULL.
So, I would restate the bug as
A function defined by a behavior can be run by referencing its owner
%this.object.foo();
or the behavior's instance:
%this.object.behaviorInstance.foo();
However, when the function is called from the object, it always returns NULL. Referencing the behavior works as intended.
#4
%this.object.foo();
Calls the "foo" function of the object, if one exists, and returns that value. If the object has any behaviors with "foo" functions, those functions will also be called.
%this.object.behaviorInstance.foo();
Calls the "foo" function of a specific behavior instance, and returns that value. Does not call the "foo" function of the object or any other behaviors on that object.
For a case where the difference is significant, consider the onLevelLoaded function, which is quite likely to exist both on the object itself and on more than one behavior of the object.
04/14/2008 (2:35 pm)
I'm not sure that's a bug - those two calls are not equivalent.%this.object.foo();
Calls the "foo" function of the object, if one exists, and returns that value. If the object has any behaviors with "foo" functions, those functions will also be called.
%this.object.behaviorInstance.foo();
Calls the "foo" function of a specific behavior instance, and returns that value. Does not call the "foo" function of the object or any other behaviors on that object.
For a case where the difference is significant, consider the onLevelLoaded function, which is quite likely to exist both on the object itself and on more than one behavior of the object.
#5
I guess it depends on what is and is not a bug. :)
Using your example, my expectation would as follows:
%this.object.foo();
Calls the "foo" function of the object, if one exists, and returns that value. If the object has any behaviors with "foo" functions, those functions will also be called and returns that value .
I can see that this may cause problems if "foo" is defined on the object and the behavior, or in multiple behaviors and it returns a value. However, I prefer the flexibility to allowing the return values and shoulder the responsibility of managing it (perhaps a error message if a function generates more than one return value?)
If this not a bug, then TS should produce at the very least produce a warning message. Otherwise, this functionality difference is subtle and potentially confusing.
04/15/2008 (3:56 am)
Kalle,I guess it depends on what is and is not a bug. :)
Using your example, my expectation would as follows:
%this.object.foo();
Calls the "foo" function of the object, if one exists, and returns that value. If the object has any behaviors with "foo" functions, those functions will also be called and returns that value .
I can see that this may cause problems if "foo" is defined on the object and the behavior, or in multiple behaviors and it returns a value. However, I prefer the flexibility to allowing the return values and shoulder the responsibility of managing it (perhaps a error message if a function generates more than one return value?)
If this not a bug, then TS should produce at the very least produce a warning message. Otherwise, this functionality difference is subtle and potentially confusing.
#6
1) If multiple "foo" functions exist, you'd end up trying to return multiple values at once - not something that's really possible.
2) Causing an error when multiple return values are present would break existing functions that use the object as soon as behaviors were added.
04/15/2008 (4:59 pm)
There's two problems with that:1) If multiple "foo" functions exist, you'd end up trying to return multiple values at once - not something that's really possible.
2) Causing an error when multiple return values are present would break existing functions that use the object as soon as behaviors were added.
#7
Thanks for your feedback.
1)I don't want to multiple return values from different functions and expect that this would fail (and generate an error message!)
2) As for it breaking existing things, I'm ok with that. If TS gives me an error message that what I did was wrong, I can work around it. However, having a single function that can be called on different objects that is implemented through different behaviors is very useful. Furthermore, the fact that you can RUN the function with the behavior reference, but just not RETURN a value is confusing and cumbersome.
04/16/2008 (5:29 am)
Kalle,Thanks for your feedback.
1)I don't want to multiple return values from different functions and expect that this would fail (and generate an error message!)
2) As for it breaking existing things, I'm ok with that. If TS gives me an error message that what I did was wrong, I can work around it. However, having a single function that can be called on different objects that is implemented through different behaviors is very useful. Furthermore, the fact that you can RUN the function with the behavior reference, but just not RETURN a value is confusing and cumbersome.
#8
04/16/2008 (2:20 pm)
I can how that would be useful, although I still think it should have different semantics than a normal function call on the object. Perhaps a form of the "call" function? For instance, here's a quick hacked version (would need source modification to accept an arbitrary number of arguments, though):// Call a function on an object and all it's behaviors, return the result.
// Note: In the case that multiple behaviors or the object and a behavior both possess
// the function in question, only one value will be returned and an error will be reported.
// Example: %score = %object.callEvery("getScore");
function t2dSceneObject::callEvery(%this, %function, %p1, %p2, %p3, %p4, %p5)
{
%count = 0;
%result = "";
if(%this.isMethod(%function)) {
%result = %this.call(%function, %p1, %p2, %p3, %p4, %p5);
%count++;
}
for(%i=0; %i<%this.getBehaviorCount(); %i++)
{
%inst = %this.getBehaviorByIndex(%i);
if(%inst.isMethod(%function)) {
%result = %inst.call(%function, %p1, %p2, %p3, %p4, %p5);
%count++;
}
}
if(%count > 1)
error("callEvery - Object " @ %this @ " has more than one behavior with function " @ %function @ "!");
return %result;
}
Associate Orion Elenzil
Real Life Plus
are you sure those are balanced right ?
have you tried putting some print statements inside getData() to verify that %this is what you expect ?