Sign in to follow this  

Registrating one's Superclass

This topic is 3095 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello I'm new with Angelscript and I'm wonderring, if there is a possibility in Anglescript to registrate a class's baseclasses, like in luabind. In order not to need to registate all Members and Methods twice ? Previously thank You for any help.

Share this post


Link to post
Share on other sites
Currently AngelScript doesn't support that directly. However, you can reduce the amount of code you need to write by using function grouping. An example of that is around the middle of this thread.

Share this post


Link to post
Share on other sites
No, AngelScript can't do that. Since AngelScript (mostly) doesn't use wrapper functions when registering the interface there is no way for the engine itself to provide this information. A method pointer is not necessarily the same for the base class and the derived class, especially if the derived class inherits from more than one base class.

However, if you follow the advice in the manual (Registering class hierarchies) you'll be able to reduce the manual work for the registration quite a bit.

PS. The article in the manual was based mostly on the discussion from the thread that SiCrane mentioned.

Regards,
Andreas

Share this post


Link to post
Share on other sites
Ah, I see. So there won't be throwen an exception when I registrate a overwritten method.

For example:

class Base{
virtual void aMethod() { ... }
};

class Derived : Base{
void aMethod() { ... }
};

int r;

// Register the base type
r = engine->RegisterObjectType("derived", sizeof(Derived), asOBJ_REF); assert( r >= 0 );

// Register the mehtod of the baseclass
r = engine->RegisterObjectMethod("derived", "void aMethod()", asMETHOD(Base, aMethod), asCALL_THISCALL); assert( r >= 0 );

// Register the mehtod of the derived class
r = engine->RegisterObjectMethod("derived", "void aMethod()", asMETHOD(Derived, aMethod), asCALL_THISCALL); assert( r >= 0 );


Another question:

Will there be a possibility for an direct access by the AS-API to the meta-information about the registrated ObjectTypes in future ?
A kind of reflection like in C# or java.

Share this post


Link to post
Share on other sites
Quote:
Original post by WitchLord
No, AngelScript can't do that. Since AngelScript (mostly) doesn't use wrapper functions when registering the interface there is no way for the engine itself to provide this information. A method pointer is not necessarily the same for the base class and the derived class, especially if the derived class inherits from more than one base class.

Couldn't you use the implicit ref cast behavior to get a pointer to the base and use that to call the base class methods on derived objects? Off the top of my head, that seems like all the information you'd need to get pointers to members for the base to work with the derived class. On the downside, it'd probably be less efficient than using the derived type's member function pointers.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
Couldn't you use the implicit ref cast behavior to get a pointer to the base and use that to call the base class methods on derived objects? Off the top of my head, that seems like all the information you'd need to get pointers to members for the base to work with the derived class. On the downside, it'd probably be less efficient than using the derived type's member function pointers.


That might be possible, I'll have to give this a try some day.

Share this post


Link to post
Share on other sites
Quote:
Original post by _matthias_

// Register the mehtod of the baseclass
r = engine->RegisterObjectMethod("derived", "void aMethod()", asMETHOD(Base, aMethod), asCALL_THISCALL); assert( r >= 0 );

// Register the mehtod of the derived class
r = engine->RegisterObjectMethod("derived", "void aMethod()", asMETHOD(Derived, aMethod), asCALL_THISCALL); assert( r >= 0 );




You should only register the derived class' method. Otherwise you'll tell AngelScript that there are two versions of the same function, which will cause ambiguity in the script compilation.


Quote:
Original post by _matthias_
Another question:

Will there be a possibility for an direct access by the AS-API to the meta-information about the registrated ObjectTypes in future ?
A kind of reflection like in C# or java.


This access is available already. However, the application needs to implement the necessary functions to query the meta-information in the way you want it.

I'll make further improvements towards better support for reflection in upcoming releases. But feel free to send me suggestions for how you would like it to work.

Share this post


Link to post
Share on other sites
Quote:
Original post by WitchLord
You should only register the derived class' method. Otherwise you'll tell AngelScript that there are two versions of the same function, which will cause ambiguity in the script compilation.


But this double registrating would be autmatically made by your template construction, doesn't it?

Quote:
Original post by WitchLord
I'll make further improvements towards better support for reflection in upcoming releases. But feel free to send me suggestions for how you would like it to work.


I'm writting a little 3D modeling, animation & rendering tool specially for the use in schools.
Here a screenshot: description of your image

On the right side you ca nsee the Channel Box or in German "Eigenschaften". This window is gereatated autmatically by a selfmade reflecting system. But I would be glad to be able to use angelscript for these too. Important to realize this is to get a list of all members (and methods) a class has.

The primary use of Angelscript is to be bind all features in this tool to the script, in order to make this tool programmable at runtime and to offer Redo and Undo functionality and a interface to save/load szenes.

Are you of the opinion, that all these could be possible with Angelscript ?

By the way another question to Angelscipt:
How fast could Angelscript be in calling highly frequently a simple function like "float wave(float x, float y) { return sin(sqrt(x^2+y^2)); }" , which is used in this sample ( by the Scriptlanguage Lua): description of your image

Makes it sense to animate this with angelscript ?


Share this post


Link to post
Share on other sites
You can find out information about a script class via the asIObjectType interface. You can query the class' property information by using GetPropertyCount() to find the number of properties and then GetPropertyTypeId() and GetPropertyName() to find the name and type of each property. Similarly you can use GetMethodCount() to find the number of methods the class has and GetMethodDescriptorByIndex() to get a asIScriptFunction that will tell you about the method.

Share this post


Link to post
Share on other sites
Quote:
Original post by _matthias_
But this double registrating would be autmatically made by your template construction, doesn't it?


Actually not. If you look carefully, you'll see that the registering the derived class first calls the function for registering the base class' methods, and then only register the new methods introduced by the derived class. It doesn't register the methods it inherits more than once.



Quote:
Original post by _matthias_
Are you of the opinion, that all these could be possible with Angelscript ?


Yes, definitely. And also quite easily. SiCrane already showed how to enumerate the properties of a class, and I'll also help you clear up any questions you might have.

Be sure to let me know if you need some feature that is not available in AngelScript, and I'll see what I can do to add it in a future release.



Quote:
Original post by _matthias_
By the way another question to Angelscipt:
How fast could Angelscript be in calling highly frequently a simple function like "float wave(float x, float y) { return sin(sqrt(x^2+y^2)); }" , which is used in this sample ( by the Scriptlanguage Lua):

Makes it sense to animate this with angelscript ?



Lua has more people working on it, and has also been around for a much longer time, but I'm willing to bet that even if AS is not currently as fast or faster than Lua in this example, I can easily optimize it to be so. I'm not saying this because I think I'm better than the developers of Lua (which would probably not be true), but rather that AS allows it to be executed much faster due to being statically typed, rather than dynamically typed. There are just less things to do at run time. (LuaJIT is another matter though, as it will produce machine code rather than byte code)

Please let me know if you find that AngelScript is slower, and I'll put in an effort to add some more optimizations.

I look forward to seeing more on your work with AngelScript.

Share this post


Link to post
Share on other sites
After some stressfull days I' m in touch now.

I' tried to do a benchmarktest with Lua and AngelScript.

The Code for the while-loop is as the follow (AngelScript only):

// Initialize Values
QueryPerformanceCounter((LARGE_INTEGER*)&LastCount);
QueryPerformanceCounter((LARGE_INTEGER*)&CurCount);

curFrame = 0;

// This while loop will be run until one second is over
while(CurCount - LastCount < Frequency) {
curFrame++;
// Every 10000th time look, if one second is over
if(curFrame % 10000 == 0) QueryPerformanceCounter((LARGE_INTEGER*)&CurCount);

r = ctx->Prepare(funcId);

// Now we need to pass the parameters to the script function.
ctx->SetArgFloat(0, value_1);
ctx->SetArgFloat(1, value_2);
ctx->SetArgFloat(2, value_3);

// Execute
r = ctx->Execute();

if( r != asEXECUTION_FINISHED )
{
// The execution didn't finish as we had planned. Determine why.
if( r == asEXECUTION_ABORTED )
cout << "The script was aborted before it could finish. Probably it timed out." << endl;
else if( r == asEXECUTION_EXCEPTION )
{
cout << "The script ended with an exception." << endl;

// Write some information about the script exception
int funcID = ctx->GetExceptionFunction();
asIScriptFunction *func = engine->GetFunctionDescriptorById(funcID);
cout << "func: " << func->GetDeclaration() << endl;
cout << "modl: " << func->GetModuleName() << endl;
cout << "sect: " << func->GetScriptSectionName() << endl;
cout << "line: " << ctx->GetExceptionLineNumber() << endl;
cout << "desc: " << ctx->GetExceptionString() << endl;
}
else
cout << "The script ended for some unforeseen reason (" << r << ")." << endl;
}

}


The most of the Lines are copied from the documentation.

But the results are, as far as I made no mistakes, quite good for AngelScript.
This function in AngelCode:

float wave(float x, float y, float t) {
return sin(sqrt(x*x+y*y));
}


was called 460 000 times per second.

A similar function in Lua was called 260 000 times per socond.

The results are rounded by 10 000.( See in the Code^^)

Another usue:

I'm writing an German articel about AngelScript in Wikipedia.org, do you allow me to use code-samples and images from your website therefor ?





Share this post


Link to post
Share on other sites
I'm pleased to see that AngelScript is really faster than Lua. From what I can tell, you're doing everything correctly. *(float*)ctx->GetArgPointer(0) = value; is slightly faster than using ctx->SetArgFloat(0, value);, but I don't think changing this will show any noticeable difference.

However, if you build the AngelScript library without multithread support you'll get an extra boost in performance. If you also set the engine property asEP_BUILD_WITHOUT_LINE_CUES you can get even more speed. Obviously, you need to evaluate if you don't need the stuff you disable by this.

If you really need it, I'm sure I can optimize the library even further.


As for the question about Wikipedia, yes, you may use samples and images from my site if you wish.

Share this post


Link to post
Share on other sites
After a little practice with Angelscript I came to one problem:

I tried to registrate a class, heritated from a base class, as you have shown at in the documantation:

I' m not sure what Flags I should use for registrating the Object-Types so I wrote these lines of code:

void RegisterTypes(asIScriptEngine *engine)
{
int r;

// Register the base type
r = engine->RegisterObjectType("base", sizeof(Base), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CA); assert( r >= 0 );
RegisterBaseMembers<Base>(engine, "base");

// Register the derived type
r = engine->RegisterObjectType("derived", sizeof(Derived), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CA); assert( r >= 0 );
RegisterDerivedMembers<Derived>(engine, "derived");
}



Registrations:

template <class T>
void RegisterBaseMembers(asIScriptEngine *engine, const char *type) {
int r;

r = engine->RegisterObjectMethod(type, "void IncreasePropertys()", asMETHOD(T, IncreasePropertys), asCALL_THISCALL); assert( r >= 0 );

r = engine->RegisterObjectProperty(type, "int BaseProperty", offsetof(T, BaseProperty)); assert( r >= 0 );
r = engine->RegisterObjectBehaviour(type, asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(BaseDefaultConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectBehaviour(type, asBEHAVE_CONSTRUCT, "void f(const base &in)", asFUNCTION(BaseCopyConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectBehaviour(type, asBEHAVE_DESTRUCT, "void f()", asFUNCTION(BaseDestructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
}

''And for the derived class''
template <class T>
void RegisterDerivedMembers(asIScriptEngine *engine, const char *type) {
int r;

RegisterBaseMembers<T>(engine, type);

r = engine->RegisterObjectProperty(type, "int DerivedProperty", offsetof(T, DerivedProperty)); assert( r >= 0 );
r = engine->RegisterObjectBehaviour(type, asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(DerivedDefaultConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectBehaviour(type, asBEHAVE_CONSTRUCT, "void f(const derived &in)", asFUNCTION(DerivedCopyConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectBehaviour(type, asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DerivedDestructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );

}


Everythig works but registrating derives destructer makes assertion failing.
Registrating constructers twice does not matters, but destructer does.^^
How can I solve this problem ?

Share this post


Link to post
Share on other sites
I'm not sure what you're trying to do is supported by AngelScript. According to the documentation page you linked to:
Quote:
Hierarchies can currently only be registered for reference types, not for value types.

Share this post


Link to post
Share on other sites
You can't register the behaviours inside the RegisterBaseMembers and RegisterDerivedMembers. It doesn't make sense to register the Base class' constructors and destructor for the Derived class.

If you don't want to split the registration in two functions, then you could pass a flag to the function to tell if the behaviours should be registered or not.


template <class T>
void RegisterBaseMembers(asIScriptEngine *engine, const char *type, bool registerDerived)
{
int r;

r = engine->RegisterObjectMethod(type, "void IncreasePropertys()", asMETHOD(T, IncreasePropertys), asCALL_THISCALL); assert( r >= 0 );

r = engine->RegisterObjectProperty(type, "int BaseProperty", offsetof(T, BaseProperty)); assert( r >= 0 );

if( !registerDerived )
{
r = engine->RegisterObjectBehaviour(type, asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(BaseDefaultConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectBehaviour(type, asBEHAVE_CONSTRUCT, "void f(const base &in)", asFUNCTION(BaseCopyConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectBehaviour(type, asBEHAVE_DESTRUCT, "void f()", asFUNCTION(BaseDestructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
}
}


Share this post


Link to post
Share on other sites
But what if I don't know whether a method or behaviour should be overload.

How can I registrate the following classse in the shortest and dynamicly way ?

[source lang=cpp]

class base{
public:
base() : valueBase(23) {}
~base() {}

virtual int GetSumOfAllProperties() {return valueBase; }

protected:
int valueBase;
};

class derived_1 : base{
public:
derived_1() : base(),valueDerived(12) {}
~derived_1() {}

virtual int GetSumOfAllProperties() {return valueBase+valueDerived; }

protected:
int valueDerived;
};

class derived_2 : base{
public:
derived_2() : base() {}
~derived_2() {}

virtual int GetSumOfAllProperties() {return valueBase; }

void SetBaseProperty(int value) { valueBase = value; }

};



Of curse this Code deos not make real sense, but it shows what I need.

In my case I get the Error Message: "Multiple matching signatures to ...".
I would be glad, if AngelScript would only use the last registrated method.
This would make some things easier.

Share this post


Link to post
Share on other sites
You don't need to know if a method is being overloaded or not. You just need to know what class implements the function first.

The following ought to work:


template <class T>
void Constructor(void *memory)
{
// Initialize the pre-allocated memory by calling the
// object constructor with the placement-new operator
new(memory) T();
}

template <class T>
void Destructor(void *memory)
{
// Uninitialize the memory by calling the object destructor
((T*)memory)->~T();
}

template <class T>
void RegisterCommonBase(asIScriptEngine *engine, const char *type)
{
int r;

// If the constructor and destructor behaviours are implemented
// through a templated wrapper, we can actually register them
// with one common function.
r = engine->RegisterObjectBehaviour(type, asBEHAVE_CONSTRUCTOR, "void f()", asFUNCTION((Constructor<T>)), asCALL_CDECL_OBJLAST);
r = engine->RegisterObjectBehaviour(type, asBEHAVE_DESTRUCTOR, "void f()", asFUNCTION((Destructor<T>)), asCALL_CDECL_OBJLAST);

r = engine->RegisterObjectMethod(type, "int GetSumOfAllProperties()", asMETHOD(T, GetSumOfAllProperties), asCALL_THISCALL); assert( r >= 0 );
}

void RegisterBase(asIScriptEngine *engine)
{
int r;
r = engine->RegisterObjectType("base", sizeof(base), asOBJ_VALUE | asOBJ_APP_CLASS_CD);
RegisterCommonBase<base>(engine, "base");
}

void RegisterDerived_1(asIScriptEngine *engine)
{
int r;
r = engine->RegisterObjectType("derived_1", sizeof(derived_1), asOBJ_VALUE | asOBJ_APP_CLASS_CD);
RegisterCommonBase<derived_1>(engine, "derived_1");

// derived_1 doesn't implement any new methods/behaviours, so there's nothing more to do
}

void RegisterDerived_2(asIScriptEngine *engine)
{
int r;
r = engine->RegisterObjectType("derived_2", sizeof(derived_2), asOBJ_VALUE | asOBJ_APP_CLASS_CD);
RegisterCommonBase<derived_2>(engine, "derived_2");

// Register the new methods that derived_2 implements
r = engine->RegisterObjectMethod(type, "void SetBaseProperty(int)", asMETHOD(derived_2, SetBaseProperty), asCALL_THISCALL); assert( r >= 0 );
}




Since C++ doesn't let you take the address of the constructor or destructor these need a wrapper function. By implementing the wrapper with a template you can actually reuse the registration code for these as well as seen above. I know, this contradicts what I said in the earlier post. ;)

It is an error to register the same method twice. AngelScript really should give an error when this is done, but I haven't implemented that check yet. I can't remove the compiler error in this case, because there is really no way of knowing that the error is caused because you knowingly registered the same function twice (which you shouldn't have done, in the first place). In your case, it would have worked, but consider the case when the registration is done from dynamically loaded plugins that you don't have much control over. In this case it might be disastrous to allow the multiple functions, since the two function may actually do completely different things.

Share this post


Link to post
Share on other sites

This topic is 3095 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this