Game Development Community

Console Functions: How is the namespace determined?

by Demolishun · in Torque 3D Professional · 12/17/2011 (7:24 pm) · 1 replies

Okay, this may take some brain damage to explain.

Right now I am registering a callback using the function:
Con::addCommand

This is being done through a python interface. I am storing a callback to a Python object in this structure:
static HashTable<Namespace::Entry*,void*> scriptCallbackLookup;

As you can see the Namespace::Entry is used to keep track of the python object which I cast to void *. The reason I cast it is because I intend to support more than just Python callbacks in the future.

So, the problem is coming from this:
SomeNamespace::somefunction();

If I register a function like the above it works fine and it does not matter if the namespace actually exists yet. This allows me to define namespace functions before the objects I use it with exist. So what is the issue? The issue is calling the above function without an object puts me at a dead end. I get the call to my callback function, but when I want to lookup the function in the namespace the only information available to me is the function name, not the name space. Normally you would attach an object and call it like this:
someobject.somefunction();
or
SomeNamespace::somefunction(someobject);

Either way if the object has the somefunction defined against its namespace it will work. However, if no namespace is defined shouldn't the console treat it as a function and return "SomeNamespace::somefunction"? Somewhere it is chopping off the SomeNamespace:: portion even if called explicitly. This makes it impossible to determine the namespace the function is supposed to be called against unless you provide an object.

I am guessing conceptually I am thinking about this wrong so I came up with some questions to try and reframe my thoughts:
1. Is there ever a time when you would call the function explicitly (SomeNamespace::somefunction) without an object?
2. Where in the code (I have searched everywhere I can think of) does it actually separate the namespace value from the function value?
3. Should I just require a minimum of 1 object/parameter and if I don't get an object, or an object with the proper namespace then just error out? I just not sure what is the standard for Torque functions. I would like to stay consistent.

I know there is a way to determine namespace, but it involves inserting code into the compiledeval.cc code. Not a good solution in my opinion.

Edit:
Interestingly enough I made it so the first parameter can be checked against being a simobject. If it is I get the namespace for that simobject and call the function associated with that namespace. However, it will not be the explicitly defined namespace:
new ScriptObject(TestNS1){
   className = TestNSA;
};
new ScriptObject(TestNS2){
   className = TestNSB;
};
function TestNSA::somefunction(){
   echo("TestNSA::somefunction");
}
function TestNSB::somefunction(){
   echo("TestNSB::somefunction");
}
// If you call this you get what you expect
TestNS1.somefunction();
TestNS2.somefunction();
// This will call the namespace of the object
// The actual function called will be TestNSB::somefunction
TestNSA::somefunction(TestNS2);

As you can see it could be confusing when using the first parameter as the object. So maybe I should not allow it for my callbacks. If I run this example in TS it does call TestNSA::somefunction like it should because it explicitly calls the function. However, I cannot duplicate this as my callback cannot assume which method called it, and the data provided to the function when calling it with the explicit prefix of the namespace does not keep the namespace information in tact when invoking the callback.

Hmmm, I wonder if I can do a stack trace in this case to determine which command was actually called. That would give me the namespace prefix if any.

Edit (again):
Ahh, darn it. Backtrace will work for console functions defined in script, but does not seem to work inside a C++ callback. That really sucks. I get absolutely no data back in my callback even though the function would technically still not have returned. I wonder if I have to tell it to update the current stack state or something?

About the author

I love programming, I love programming things that go click, whirr, boom. For organized T3D Links visit: http://demolishun.com/?page_id=67


#1
12/18/2011 (3:49 am)
Okay, I have decided to nix the ability to explicitly call a function with a namespace prefix. The reason is because the callback accepts strings. A string can contain any type of data. There is no way to ensure that the string does not match to an object or not. It creates an ambiguous situation:
function TestNS::function1();
function function1(value);
If I put "TestNS" in the value parameter for function1 then the code that looks up the namespace object will find that string and decide the object was passed. Then it looks up the namespace and finds the TestNS::function1 function instead of function1 which is in the global namespace. So the wrong function will get called.

Unless I can find a way to reliably determine what namespace the code I am running is in then the only way to get the namespace will be by the SimObject supplied. I really don't want to insert code into compiledEval.cc to fix this. Not that important.

Edit:
@GG,
I think that when you call a callback registered with Con::addCommand then it should provide a way inside the callback to determine the actual function namespace. Right now it is assumed as you only have one function per command. However, with a callback that handles multiple console functions there is no easy way to tell. Conversely you can tell inside of a pure script function. I would like to classify this as a bug.

Here is the function I am using to register the commands:
void script_export_callback_string(StringCallback cb, const char *nameSpace, const char *funcName, const char* usage,  S32 minArgs, S32 maxArgs);
It is defined in "c_scripting.cpp".