Game Development Community

Messed-up Namespace Linkage

by Michael Woerister · in Torque Game Builder · 08/12/2006 (11:07 am) · 11 replies

Hi, there seems to be a bug in namespace linkage.

If you do the following then the scriptObject won't recognize it's delete() method anymore:
function MySingleton::setXYZ(%this, %arg)
{
    %this.xyz = %arg;
}

function MySingleton::create()
{
    $MySingleton = new ScriptObject(MySingleton);
}

function MySingleton::destroy()
{
    $MySingleton.delete();    
}

MySingleton::create();
$MySingleton.setXYZ( "abc" );
MySingleton::destroy();

You get this error message:
Quote:
TGB/gameScripts/game.cs (0): Unknown command delete.
Object (2162) MySingleton -> ScriptObject -> SimObject

delete() clearly is in the SimObject namespace and should be found...

-Michael

#1
08/13/2006 (5:32 pm)
It's the create method that is messing it up. Try renaming that to MySingleton_create() and it should work. It could be a bug, but that's the workaround.
#2
08/14/2006 (2:47 am)
Yeah, I already worked around it ;)

It's just MySingleton::create() would look much nicer and consistent.
#3
08/14/2006 (8:12 am)
Two other points that I didn't mention the first time around.

Your destroy method is also not implemented properly:
function MySingleton::destroy(%this)
{
    %this.delete();
}

Your constructor doesn't properly implement the singleton pattern:
function MySingleton_create()
{
    if (! isObject(MySingleton))
    {
        new ScriptObject(MySingleton);
    }
}

If you want it to look consistent, you could do it this way:
function MySingleton::getInstance(%this)
{
    if (! isObject(MySingleton))
    {
        new ScriptObject(MySingleton);
    }
}

And you'd have to call it with:
%singleton = MySingleton::get(0);
though I really think the _create method is much more elegant. Do you want things to look elegant in the definitions or to be elegant in terms of coding style? The style would dictate to not scope the create method to the object, since no object exists to call it on.
#4
08/15/2006 (1:25 am)
That was just some minimal code to reproduce the bug.
I wanted to use the methods like you use static methods in c++. It's done in the animation builder code and it works to some extent. I just wanted to have the create() function in the same namespace as all the other functions of that object.
#5
08/15/2006 (4:56 am)
Actually, couldn't getInstance() look something like this:
function MySingleton::getInstance() // "static" function
{
    if (! isObject(MySingleton))
    {
        MySingleton::create();
    }

    return MySingleton;
}
#6
08/15/2006 (5:03 am)
It should but there seems to be a problem with namespace linkage when you mix static and non-static methods.
#7
08/15/2006 (8:10 am)
The traditional static concept doesn't make sense in TS because TS is not OO. If you're thinking in terms of "static" then all methods in TS are static and can be called from a static context. Even methods that appear to be scoped to an object. TS is OO-like but all of its OO-like constructs are syntactic sugar over a non-OO system.
#8
08/15/2006 (9:09 am)
Well, then I just want to have the create() function in the MySingleton namespace. In a non-OO language with namespaces there shouldn't be a problem with having some function in some namespace without any parameters.
#9
08/31/2006 (11:56 am)
Hey guys,
Sorry I'm so late to this party but I did some looking into this problem today and I've come up with a solution. I need to check with a few people that have a much more indepth knowledge of the internal workings of the console before I can call this a 'fix' and implement it in TGB but I'm fairly confident this is correct. In any way it does make the script you have in your original post work properly.

Techno Babble

The problem here turned out to be that because the namespace was already declared as a function before it was linked to an object, when the object namespace linking occurs it was unnecessary for it's name to be inserted into the hashtable (It already existed). Because of this the hashtable cache was not cleared and rebuilt which caused the link lookup to be improper when you called a method on an object of that class. With this in mind, I simply added the following below which causes the hashtable for namespaces to be rebuilt when you link or unlink a namespace.

End Techno Babble

***Use at your own risk*** - Unconfirmed fix

Open consoleInternal.cc and change change the following two functions to include the bold trashCache call. This causes the hash table to rebuilt and subsequent lookups will succeed where they failed before. I'll repost here once I have a final solution, but this should unstick you guys that can't stay out of the source :)

bool Namespace::unlinkClass(Namespace *parent)
{
   Namespace *walk = this;
   while(walk->mParent && walk->mParent->mName == mName)
      walk = walk->mParent;

   if(walk->mParent && walk->mParent != parent)
   {
      Con::errorf(ConsoleLogEntry::General, "Error, cannot unlink namespace parent linkage for %s for %s.",
         walk->mName, walk->mParent->mName);
      return false;
   }

   mRefCountToParent--;
   AssertFatal(mRefCountToParent >= 0, "Namespace::unlinkClass: reference count to parent is less than 0");

   if(mRefCountToParent == 0)
      walk->mParent = NULL;

   [b]trashCache();[/b]

   return true;
}


bool Namespace::classLinkTo(Namespace *parent)
{
   Namespace *walk = this;
   while(walk->mParent && walk->mParent->mName == mName)
      walk = walk->mParent;

   if(walk->mParent && walk->mParent != parent)
   {
      Con::errorf(ConsoleLogEntry::General, "Error: cannot change namespace parent linkage for %s from %s to %s.",
         walk->mName, walk->mParent->mName, parent->mName);
      return false;
   }
   mRefCountToParent++;
   walk->mParent = parent;

   [b]trashCache();[/b]

   return true;
}

Hope this helps, Cheers!

-Justin
#10
09/01/2006 (10:49 am)
Thanks Justin! I hope this gets confirmed.
#11
09/01/2006 (10:52 am)
Michael,
Hey I checked with Ben Garney the other day, we sat down and looked at the problem and solution and we both agree it is infact proper. The only thing left to do is to test it to make sure that there are no performance implications as trashing the cache requires a hashtable rebuild. I don't suspect it will, but better safe than sorry :)

Cheers,
-Justin