Advertisement

AngelScript and PImpl

Started by August 13, 2015 12:49 AM
2 comments, last by WitchLord 9 years, 3 months ago

asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

This line of code demonstrates something that I greatly dislike about the AngelScript API (though, aside from this the API is excellent for C++ bindings). Maybe I'm missing something here, but I don't understand why something like this:


asScriptEngine engine;

Couldn't have been implemented. What's the purpose of using PImpl? Seems like a waste of performance if you ask me (not to mention the ANGELSCRIPT_VERSION is finally gone, what exactly does that do, anyways? seems like a redundant macro to be passing to the library).

Some other examples include asIScriptEngine::GetModule and asIScriptModule::GetFunctionByDecl which both return PImpl's.

I'd like to see a version where pointers aren't just thrown everywhere. Not only does dynamic memory come with a performance cost (maybe performance and scripting don't go hand-and-hand, but I feel this is still a concern), but they make it unclear who owns what object, the object's lifetime, and not to mention the lack of RAII to automatically call any cleanup functions (unless the library does it for you somehow, then you can ignore the last one).

Unless there is a reason for them, but that's why I'm asking.

- Management

The main benefit of using abstract classes (interfaces) like this is that the application doesn't need to know the internals of the library at compilation or linker time. This allows the library to be dynamically loaded and instantiated as a plugin.

The ANGELSCRIPT_VERSION argument to asCreateScriptEngine() goes along with that. By having the application provide the version of the library it has been compiled to use, AngelScript can validate this at runtime in order to avoid runtime crashes in case the application is expecting a different version of the library than is actually available.

I understand that you have no interest in loading the script library dynamically so these benefits have absolutely no meaning for you, but AngelScript is not written for just a single application in mind. There plenty of other application developers that are thankful for the abstract classes, because without them they would have to implement the abstraction layer themselves;

You're right that dynamic (heap) memory has an overhead compared to local (stack) memory, but in practice, for the AngelScript object instances that you'll interact with this overhead is negligible. I cannot imagine any practical use of AngelScript where you would create a script engine instance locally for use only within that single function (not counting the main function, of course).

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement

The main benefit of using abstract classes (interfaces) like this is that the application doesn't need to know the internals of the library at compilation or linker time. This allows the library to be dynamically loaded and instantiated as a plugin.

True. But AngelScript as a plugin? Does it even work as a plugin? I haven't ventured beyond the C++ binding API, so correct me if I'm wrong, but wouldn't the application require knowledge of AngelScript before hand to bind it? It wouldn't really be a plugin if the application needs it. It would just be a dynamically-loaded library.

The ANGELSCRIPT_VERSION argument to asCreateScriptEngine() goes along with that. By having the application provide the version of the library it has been compiled to use, AngelScript can validate this at runtime in order to avoid runtime crashes in case the application is expecting a different version of the library than is actually available.

I hadn't thought about that.

I understand that you have no interest in loading the script library dynamically so these benefits have absolutely no meaning for you, but AngelScript is not written for just a single application in mind. There plenty of other application developers that are thankful for the abstract classes, because without them they would have to implement the abstraction layer themselves;

I don't mean to come off as rude, but would you mind giving me an example of AngelScript saving the day with PImpl? The library seems virtually exclusive to game engines, which certainly don't dynamically load modules as important as the scripting libraries. I know the library's usages can extend beyond just games, but it makes it that much harder to understand a true scenario where PImpl is important. It just seems like a very weird scenario to plan for given how the library is typically used. Lua uses a form of PImpl (or whatever it's called in C), it's used well beyond just games, yet the only scenario I've heard about it benefiting (I say benefiting loosely, because re-compiling wouldn't be that much of a hassle) from it's PImpl-like interface was to simply update the library's DLL without re-compiling while maintaining the ABI.

You're right that dynamic (heap) memory has an overhead compared to local (stack) memory, but in practice, for the AngelScript object instances that you'll interact with this overhead is negligible. I cannot imagine any practical use of AngelScript where you would create a script engine instance locally for use only within that single function (not counting the main function, of course).

I don't mean to sound like this is some astronomical issue. I don't believe using pointers and a bit of dynamically-allocated memory makes much of a different either (it's a scripting language that's much slower than C++, tuning for best cache performance is a relatively minor issue). As I said, Lua uses it too, I only don't care because it's written in C so it saves me from typing &s everywhere (that and Lua goes crazy with dynamically allocated memory anyhow) smile.png . It's just something that I don't quite get given the syntax of C++ would allow for clean code and stack-allocated objects.

Also, just because it's stack-allocated doesn't mean it isn't practical to just throw it in the game loop function (or even just main, like you said, if the application is not a game) and just use references. My issue is where it's allocated, not how it's referenced.


I don't mean to come off as rude, but would you mind giving me an example of AngelScript saving the day with PImpl?

'saving the day' is probably a bit too extreme. Pretty much everything can be done in multiple ways.

I do not mean to defend Pimpl over everything else. I don't use this way of coding in my other projects, but as AngelScript is a library it is nice to keep a clean interface and hiding the internal details. It makes it much easier for me to change the internals without breaking the applications that use AngelScript all the time.


The library seems virtually exclusive to game engines, which certainly don't dynamically load modules as important as the scripting libraries.

Don't be so quick on your assumptions:

1. There are plenty of non-game related applications that use AngelScript too. The scripting library is completely agnostic about what it is used for.

2. Dynamically loading modules as important as scripting libraries is more common than you might think, even in game engines. Some game engines support multiple scripting libraries, e.g. Lua and AngelScript in the same engine.


It's just something that I don't quite get given the syntax of C++ would allow for clean code and stack-allocated objects.

C++ is a very versatile language, and it supports many different coding styles, each with their own benefits and disadvantages.

My advice is just to keep an open mind, and don't try to fit everything into a single way of doing something.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

This topic is closed to new replies.

Advertisement