Sir Ementaler

Members
  • Content count

    54
  • Joined

  • Last visited

Community Reputation

1473 Excellent

About Sir Ementaler

  • Rank
    Member

Personal Information

  • Interests
    Programming
  1. shared by default

    This topic drew my interest because I had a related idea. In our application it's relatively common to create script files that serve as libraries to be #included. Although not everyone follows this trend, typically it makes sense for all or most of entities in those files to be registered as shared. They may get big and be included by multiple modules, so it probably saves some compilation time, and in case users want to implement any type of interaction between modules involving the entities, they don't have to modify the library file or come up with workarounds. As such, I have written files that have over a hundred occurrences of the "shared" keyword, at the beginning of every declaration that allows it. This is a really minor inconvenience but occasionally it gets in the way, such as when I initially forget to add it and have to insert it in several dozen lines, or when I want to temporarily make all entities non-shared to test something. It also looks too verbose to my liking. Because included files are also typically wrapped in a namespace, my idea to solve this was the following syntax: shared namespace ns { // shared namespace automatically declares all entities in corresponding block as shared class Object {} // Object is shared class void func() {} // func is shared function funcdef void VoidFunc(); // funcdefs are allowed in shared namespace blocks and act as always typedef double float64; // same applies to typedefs //int n; // error: variables cannot be shared } namespace ns { // being shared is not a property of the namespace itself, only of a particular namespace block // different namespace blocks with the same name may be declared as non-shared class Derived : Object {} // Derived is not shared shared int zero() {} // shared declaration in non-shared namespace block still allowed funcdef int IntFunc(); // funcdefs shared by default int n; // ok: n is not declared as shared } However, without support for anonymous namespaces, this might be quite inconvenient in instances where a named namespace is undesired, so later I also came up with a simpler, minimal syntax: namespace ns { shared { class Object {} void func() {} funcdef void VoidFunc(); typedef double float64; //int n; } class Derived : Object {} shared int zero() {} funcdef int IntFunc(); int n; } I think implementing one of those or a similar syntax would be helpful.
  2. AddScriptSection reads past the terminating character.

    Well, it's written in C++, not C, so... it sort of is in such a language, what with std::string storing its length and all. That aside, if a script file I load via this function contains a null character for whatever reason, I'd rather the AngelScript engine reliably produced an error than loaded only part of it. Yes, a typical C string specifically will not contain a null character unless to terminate the string, but nothing else that the AngelScript library interacts with has to act the same, not C++ strings, not file streams, not other languages that AngelScript can be potentially used with. For example, if your application loads script files created by users into an std::string, appends something significant at the end of them and runs that, a user may maliciously create a script that ends with a null character to load their part of the script but avoid loading yours, with unforeseen consequences. A valid script will not contain '\0' but that's exactly why the library has to parse them as well: to be able to report an error when an unexpected '\0' is found.
  3. How to return specific script objects from native code?

    The application cannot register any entities that rely on something only defined in scripts (even if said script is always loaded) so the straightforward approach is not an option. There are many possible workarounds though. The best one I can think of is to register an interface for GameObject to inherit from. AngelScript doesn't allow script classes to inherit from application-registered classes, but it does allow them to inherit from interfaces, and handles to interfaces can be returned, e.g. In the application: engine->RegisterInterface("GameObjectInterface"); engine->RegisterObjectMethod("GameObject_t", "GameObjectInterface@ getNearestObject()", asMETHOD(InternalGameObject, getNearestObject), asCALL_THISCALL); In the shared script section: shared abstract class GameObject : GameObjectInterface { // ... GameObject@ getNearestObject() { return cast<GameObject>(m_obj.getNearestObject()); } // ... }
  4. AddScriptSection reads past the terminating character.

    sizeof(kClass) will be the size of the kClass array including the terminating null character, so technically you specifically requested AddScriptSection to read up to and including '\0', which is an unexpected token. You should pass sizeof(kClass) - 1 to the function.
  5. Syntax suggestion for if statements

    I don't actually know a language where the above is valid but I can imagine that some exist. However, it may be worth considering that C++17 introduces a similar but more consistent and, to me, far better looking syntax, for if and switch statements, similar to that of for loops: if (auto it = m.find(10); it != m.end()) { return it->size(); } See init-statement here and here.
  6. Property setter doesn't return

    Regarding the above solution, please bear in mind the following code: class Object { float real; private float _virt; float get_virt() const { return _virt; } void set_virt(float val) { _virt = val; } } void main() { Object obj; any a; // Sets a to float 123.f a = obj.real = 123; // Would intuitively set a to float 123.f but in the proposed solution sets it to int 123 instead a = obj.virt = 123; }
  7. Using a slightly outdated 2.31.2 WIP version (but I didn't find any notes about this getting fixed), if the application registers a funcdef such as by engine->RegisterFuncdef("void voidFunc()"); the following script reports a compilation error: shared void call(voidFunc@ f) { f(); } According to the error, "Shared code cannot call non-shared function 'void voidFunc()'". This appears to be unjustified, because funcdefs are supposed to always be shared, all other parts of the application-registered interface are accessible from shared code, and the error only occurs when the function is called, rather than on any other use. The same error doesn't occur if the funcdef is defined within the script.
  8. Struggling to understand how to use references

    As stated by its documentation, the ref type "can refer to any object type (as long as it is a reference type)". However, the string type is registered as a value type. The distinction between a value type and a reference type is somewhat important in all of AngelScript, as value types don't support handles (@) or inout references (&), which, deeper down, is because they don't register garbage collection/reference counting mechanisms, thus making it unsafe to store any references to them other than the object itself. With some effort, it's possible to register string as a reference type, although consider whether the purposes you need it for are worth it.   The second problem you're experiencing is, first off, because the ref type can't hold references to strings, as explained earlier. If it were to occur for other types, make sure you're using an AngelScript version that incorporates revision 2347, such as the latest stable release (2.31.2). If updating the library version your project uses is not viable, or just if you'd rather have reasonable code, change the AngelScript function signature to "void test_pass_ref(ref@)" and the C++ one to "void test_pass_ref(CScriptHandle *arg)". There is no reason to ever use "@ &in" in AngelScript. And regardless of all that, if assigning it to the reference and passing it to the function actually worked, I guarantee that casting what's internally an std::string* to char* and printing that, wouldn't do anybody any good.
  9. We use r2351. I had viewed the repository and hadn't noticed any changes in the involved code but I could be wrong.
  10. Sample code #1: const uint8 foo = 0; int bar = foo;  Sample code #2: const uint16 foo = 0; void bar(int16) {} void main() { bar(foo); } The assertion failure happens when function asCCompiler::ImplicitConversionConstant calls asCExprValue::GetConstantDW, which expects a type of exactly 4 bytes in size.
  11. AngelScript execution speed?

    If AngelScript were as fast as your initial post claims it to be, i.e. 2.5 times slower than C++, it would likely be the fastest scripting language known to man. If, when bringing up Lua, you're thinking of this benchmark, take some time to actually read what it says and you'll find out that AngelScript performance was tested without a JIT compiler and compared against JIT-compiled Lua. Not to discredit the author, as neither could I get the only known AngelScript JIT compiler to work, but that is not a fair fight. Putting AngelScript up against C++, a language designed from the beginning to end to be efficient, whose compilers had decades to improve their optimization, is even less of a fair fight. Perhaps you ought to consider that the intended use of AngelScript does simply not require great speed. You're not supposed to use it to carry complicated calculations and find undiscovered prime numbers; it's a scripting language, use it to make things happen in games and stuff.
  12. Assigning property without a setter

    If your class is registered in a way as straightforward as you present it, the most reasonable thing to do would be to register the property as a non-virtual property. Getters and setters are only useful if it is unsafe to access the variable directly. If a setter is necessary because a change to the property may have side effects, then, well, you need a setter. AngelScript supports variable type functions but type compatibility is not verified at compile time, i.e. the function would accept arguments of any type. I don't recommend this for cases where the number of supported types is finite, but if it works for your purposes, you can read about it here. Otherwise you will unfortunately have to register multiple setters. That said, I'm not sure why you're so opposed to this idea, as you can do this without much work using a couple of C++ templates. Our project does this for a couple of methods with >10 overloads.
  13. Using AngelScript version 2.31.1, the following behaviors were observed regarding the "Value is too large for data type" warning:   The warning treats int8 and int16 as if they were unsigned and produces a warning iff the assigned value is respectively outside of the ranges 0-255 and 0-65535. The following snippet produces two warnings: int8 x = -1; int16 y = -1; The following snippet erroneously doesn't: int8 x = 255; int16 y = 65535; When a 32-bit variable overflow occurs during assigning a value to an int8 or int16 variable, the warning may be erroneously omitted. The following snippet doesn't produce a warning: int8 x = 4294967297; int16 y = 4294967297; The warning is never displayed for types int32, int64, and uint64 no matter the assigned value. The following snippet doesn't produce a warning: int x = 4294967295; int64 y = 18446744073709551616; uint64 z = 18446744073709551616; For the remaining unsigned integer types, the warning may be erroneously omitted if a 64-bit variable overflow occurs. The following snippet doesn't produce a warning: uint8 x = 18446744073709551616; uint16 y = 18446744073709551616; uint z = 18446744073709551616; I would be thankful if these issues could be fixed, especially the first one, where warnings are produced incorrectly. Some of our API functions have default arguments such as int8 arg = -1, which cause users' logs to be flooded with warnings whenever they make intensive use of them.
  14. Problem in array<interface@>

    Yes, but that doesn't relate at all to what I claimed. Notice how in C++ too, the signature "int find(const T&)" for T = int* would become "int find(int* const&)" and not "int find(const int*&)". Instantiation of a template is more than just replacing every "T" with the type name. You should be checking the signature for the type array<Item@> if you want to determine anything.
  15. Problem in array<interface@>

      To my information, that is incorrect. If you attempt to query the signature of the method, it's actually "int array::find(Item@const&in value) const" (or likely "int array::find(const Item@const&in value) const" in the WIP version I am not using). Notice the const qualifier in front of "&in", meaning that the handle should be passed by const &in reference rather than just &in, and thus it's possible to avoid creating a copy of the handle. The same signature would not be considered valid in other contexts, i.e. outside of templates. As such, outside of templates it is unnecessary and actually somewhat inefficient to use the signature you're using.