   Application Registered Classes
  First of all I would like to thank WitchLord for AngelScript. I decided to use AngelScript as the scripting engine for my current project. I certainly don't regret that decision; it was very easy to integrate AngelScript within my project. Unfortunately, it looks like I've run into a problem. Well, it isn't exactly a problem, but rather a feature that I miss. You see, I would like to create classes derived from application registered classes. There are of course other methods to implement similar functionalities, but an implementation based upon inheritance would be much easier and elegant.Judging from the AngelScript website the idea to inherit from application classes is known, but it isn't a big priority at the moment (correct me, if I'm wrong). That isn't a problem though as I'm willing to look at the problem myself. Whether I'll succeed is another question, but I think it's worth a try. Now, I've been looking around a little bit to investigate what is preventing application registered classes from being derivable. I came across the next text-fragement:Quote:A common super class for all script classesMaybe a super class for all script classes can be implemented. The super class, won't have any properties or methods. It is only used as a common base, so that all classes can be stored in a common way. It could also be seen as an interface that all classes implement.Potential drawback: Application registered classes won't always be derived from the super class, thus separating them from the script classes.Advantage: All script classes will have a common denominator, facilitating the storage of them. An application registered class that derive from an AngelScript class interface, can be registered to have this same common denominator which should make it possible to have script classes inherit from application registered classes. From this text-fragment I gather that AngelScript uses different classes for classes registered within AngelScript and classes registered by the application. If this assumption is right, then which classes are meant? I already looked at the source code, but I figured out it would be faster if I would ask it.Thanks in advance.   
  I'm very pleased to hear that you like AngelScript. I look forward to seeing what you'll do with it. Don't forget to let me know once you're ready to show your product, so that I can add it to the users list.Allowing script classes to inherit from application classes would indeed be a useful feature and one that intend to look into in the future. But as you already noted, it is a rather low priority for me at the moment as there are so many other features that I believe are far more useful that can be implemented before that.Another reason why I haven't spent much time investigating this feature, is that I have my doubts about how well it will work, and I do not want to implement a feature that will only work halfway. It would only leave the users wanting more, and I wouldn't be able to give it to them.Anyway, I'll gladly support your efforts in this regards by helping out where I can. If it works out well it be happy to incorporate it into the library.Script classes are implemented by the asCScriptObject. This class holds all the behaviours that are common to all script classes, as well as a pointer to the asCObjectType which holds the extra information, such as properties and methods declared by the script. The properties declared for the class by the script are allocated together with the asCScriptObject simply by allocating sizeof(asCScriptObject) + sizeof(properties) number of bytes. I believe that the easiest way to allow the script class to inherit from the application class, is if the application class first inherits from the asCScriptObject. That way the script engine can treat these classes just as any other script classes.It would also be possible to pass these script classes back to the application, and having the application treating the class normally (except that the application would be able to to easily call the class methods expecting to call the methods that script class overloads).Classes registered by the application are just that. The script engine doesn't wrap them in anyway, and accesses the methods and properties directly. It would be possible to implement inheritance for these classes too, if the script engine wrapped them in a special class. This would allow the VM to call methods on the wrapped class and any class that inherits from it the same way, without having to know exactly what class it is working on. The biggest problem with this, is that the wrapped class obviously can't be passed back to the application as if it was the original class. Another problem is that all the application classes would have to be wrapped the same way, which would add a lot of overhead to the scripts.   ;  That makes everything definitely a lot more clear.I think I'm first going to try the option where application classes themselves inherit from asCScriptObject. It sounds indeed like the easiest way to enable inheritance from application registered classes.Well, it's a starting point; time to work.   ;  Depending on your needs you want to try a script side only tactic. Basically, if you have an application registered class Foo that looks like: class Foo {  public:    Foo();    Foo(int a, int b);    void bar(void);    int baz(int a);    // etc.};Register the class with a name like FooInner and then create a script class that looks like:class Foo {  FooInner inner;  Foo() { inner = Foo(); }  Foo(int a, int b) { inner = Foo(a, b); }  void bar(void) { inner.bar(); }  int baz(int a) { return inner.baz(a); }  // etc.}Then you can derive your classes from the script Foo class. It won't work perfectly for all situations, but it might be a "good enough" solution.   ;  That is basically what I had in mind when I described how inheritance for arbitrary registered classes might work. If I'm not mistaken this is also called composite inheritance. ;  That's indeed an interesting solution, but I would actually be interested in passing back derived classes to the application. So, I'm afraid the solution is not "good enough". For cases of inheritance where this kind of behaviour is unneeded, I can see this working though.That being said, I've been studying how AngelScript deals with asCScriptObject and asCScriptType internally. I noticed that when asCScriptEngine::RegisterObjectType is being called, a new instance of asCObjectType is being created. I take that this is needed to the methods of the class? If this is the case, then would that mean that the asCObjectType instance could be "attached" to an application based class derived from asCScriptObject? As script based classes do that too.Furthermore I noticed that the asOBJ_SCRIPT_OBJECT flag is passed to asCObjectType objects created from script bases classes. I already saw that any objects that don't have this flag, application side classes, can't be inherited from through AngelScript. Would application side classes also have to declare this flag, or should the check for asOBJ_SCRIPT_OBJECT be removed or adapted?And one more question. I've been looking for the piece of code where asCScriptObject instances are being created. I already looked at asCBuilder::CompileClasses, but I didn't find it. Either I overlooked it or I looked at the wrong place. I figured that it would help me to know this, as application registered classes which are derived from asCScriptObject would have to be created in the same way.Oh, and if I'm taking unnecessary steps then please tell me.   ;  You can pass objects back to the application with some work:class FooScript : public Foo {  public:    FooScript(asIScriptObject * obj) : obj_(obj) { obj->AddRef(); }    ~FooScript() { obj_->Release(); }    virtual void bar(void) { asIObjectType * type = obj_->GetObjectType(); int id = type->GetMethodIdByDecl("void bar()"); asIScriptEngine * engine = obj_->GetEngine(); asIScriptContext * ctx = engine->CreateContext(); ctx->Prepare(id); ctx->SetObject(obj_); ctx->Execute(); ctx->Release();    }    virtual int baz(int a) { asIObjectType * type = obj_->GetObjectType(); int id = type->GetMethodIdByDecl("int baz(int)"); asIScriptEngine * engine = obj_->GetEngine(); asIScriptContext * ctx = engine->CreateContext(); ctx->Prepare(id); ctx->SetObject(obj_); ctx->SetArgDWord(0, a); ctx->Execute(); int to_return = ctx->GetReturnDWord(); ctx->Release(); return to_return;    }    // etc.  private:    FooScript(const FooScript &);    FooScript & operator=(const FooScript &);    asIScriptObject * obj_;};There are, admittedly, still at least three flaws with this. The first is that it doesn't play nicely with member variables, though this can be addressed with get/set property functions. The second is that I'm not sure how to check to make sure the script object actually inherits from the base class. There's a mechanism for checking implemented interfaces, but it doesn't look like there's a way to check for base classes. And, of course, there's a lot of manual boiler plate code. I've been playing with the idea of using my reflection engine in my .NET project to automagically generate both the script and communication classes, but I haven't had the chance to put a lot of time into the idea.   ;Quote:Original post by ZCCdark203That being said, I've been studying how AngelScript deals with asCScriptObject and asCScriptType internally. I noticed that when asCScriptEngine::RegisterObjectType is being called, a new instance of asCObjectType is being created. I take that this is needed to the methods of the class? If this is the case, then would that mean that the asCObjectType instance could be "attached" to an application based class derived from asCScriptObject? As script based classes do that too.The asCObjectType holds the description of the class, i.e. what behaviours it implements, what properties and members it has, and so on. All non-primitive types have an asCObjectType. Application registered classes don't need the asCObjectType for run-time operation, but script classes do, as they need to dynamically determine the details of the type.Application classes that derive from asCScriptObject may not have to include a reference to asCObjectType in each instance, but it needs to reserve the space so that script classes that inherit from it can use that space for its own asCObjectType.Quote:Furthermore I noticed that the asOBJ_SCRIPT_OBJECT flag is passed to asCObjectType objects created from script bases classes. I already saw that any objects that don't have this flag, application side classes, can't be inherited from through AngelScript. Would application side classes also have to declare this flag, or should the check for asOBJ_SCRIPT_OBJECT be removed or adapted?The application classes that inherit from asCScriptObject can probably use the asOBJ_SCRIPT_OBJECT flag too. I'm not sure if another flag is necessary to identify these 'hybrid' classes, that depends on you encountering any situation where you need to be able to diferenciate between the types.Quote:And one more question. I've been looking for the piece of code where asCScriptObject instances are being created. I already looked at asCBuilder::CompileClasses, but I didn't find it. Either I overlooked it or I looked at the wrong place. I figured that it would help me to know this, as application registered classes which are derived from asCScriptObject would have to be created in the same way.I'm not sure if application registered classes which are derived from asCScriptObject needs to be instanciated the same way as the script classes. This depends on if the class constructor has everything at compile time, or if you need to pass a asCObjectType to the constructor for extra information at run-time.Anyway, the script classes are instanciated with asIScriptObject *ScriptObjectFactory(asCObjectType *objType, asCScriptEngine *engine) that you'll find in as_scriptstruct.cpp.The factory behaviour for the script classes are stubs functions generated by the script compiler to allocate the memory and then call the script class' constructor to initialize it. There is one factory stubs for each script class constructor. These factory stubs are generated in int asCCompiler::CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)Quote:Oh, and if I'm taking unnecessary steps then please tell me.You seem to be on the right track so far.Regards,Andreas   ;Quote:Original post by SiCraneYou can pass objects back to the application with some work:class FooScript : public Foo {  ...Would the application register the FooScript class instead of Foo then? Quote:The second is that I'm not sure how to check to make sure the script object actually inherits from the base class. There's a mechanism for checking implemented interfaces, but it doesn't look like there's a way to check for base classes. There is the asIObjectType::GetBaseType method. ;Original post by WitchLordWould the application register the FooScript class instead of Foo then? No, it'd register Foo. And then use the asIScriptObject * for a FooInner script object (or one of the derived classes) to create a new FooScript object to be used wherever pointers or references to Foos would be used. So you'd have something like:  Foo * get_foo_property(asIScriptObject * obj, int prop) {    asIScriptObject * foo_inner = static_cast<asIScriptObject *>(obj->GetPropertyPointer(prop));    return new FooScript(foo_inner);  }There is the asIObjectType::GetBaseType method.Ok, I'm blind. Thanks.