Advertisement

Problem in array<interface@>

Started by August 30, 2016 02:44 PM
14 comments, last by IronHawk 8 years, 2 months ago

Hello!

I'm getting an exception on executing this code:


interface IItem {
    bool opEquals(const IItem@ &in other) const;
}

class CItem : CBase, IItem {
    bool opEquals(const IELCollectionItem@ &in other) const {
        return @this is @other;                                                                   
    }
}

class CHolder : CBase {
    private array<IItem@> m_arrItems;

    int32 indexOf(const IItem@ hItem) const {
        if(@hItem !is null) {
            return m_arrItems.find(@hItem); // <<<<< An exception is here
        } else {
            return -1;
        }
    }
}

The text of exception is "Type 'IItem' does not have a matching opEquals or opCmp method"

So in m_arrItems I have CItem handles, but an array itself is created to hold IItem handles.

Compiler says that all is OK but on execution it fails.

Thanks for letting me know about this. I will investigate it.

I suspect it can be worked around by changing the signature of opEquals to the following:

interface IItem {
    bool opEquals(const IItem & other) const;
}

That is, take the IItem by reference, rather than a reference to a handle.

Note, the problem is only identified at run-time, because the compiler doesn't know that the registered array type will try to call the opEquals method. I already have an item on my to-do list to add more compile time callbacks to allow things like this to be verified at compile time.

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

Hello Andreas!

I checked the solution you suggested.

So I changed the signature in IItem and then changed the method which actually does all the work:


class CItem : CBase, IItem {
    bool opEquals(const IItem & other) const {
        return @this is @other;                                                                   
    }
}

But at runtime I'm now getting an Access Violation in


void asCScriptEngine::CallObjectMethod(void *obj, asSSystemFunctionInterface *i, asCScriptFunction *s) const

with the call stack


asCScriptEngine::CallObjectMethod
...
CScriptArray::equals
...
CScriptArray::find
...

Maybe the reason of AV is that it's impossible to get the handle of other because it's passed to the function as an interface?

Actually it's necessary to write code like the one from my first post only because there is no default implementation of opEquals for any class type in the language.

It would be good to have something like "reference equals" as the default for opEquals (like in C# for example).

This would also allow to put an instance of any class to array without implementing opEquals.

The "reference equals" operator in AngelScript is the "is" operator. Use the array method findByRef to search an array by reference instead of by value.

The "reference equals" operator in AngelScript is the "is" operator. Use the array method findByRef to search an array by reference instead of by value.

Yes, I know that it's possible to do so, but for array containing handles it also doesn't work.

Simple example:


interface IItem {
}

class CItem : IItem {
}

array<IItem@> items;

int32 getIndexOf(const IItem@ &in hItem) {
    return items.findByRef(@hItem);
}

void check() {
    CItem@ hItem = CItem();
    items.insertLast(@hItem);
    println("Index from getIndexOf(): " + getIndexOf(@hItem));   // prints -1
    println("Index from findByRef: " + items.findByRef(@hItem)); // prints 0
}

So when we pass hItem to getIndexOf as const IItem@ the findByRef returns -1 for the object which is in array.

I need to implement a member function with signature like int32 getIndexOf(const IItem@ &in hItem) and this is not possible

using my code from topic start nor the code suggested by Andreas, nor the code with findByRef suggested by Sir Ementaler.

That appears to be some sort of a side effect, possibly a bug, of passing the handle by non-const &in reference. There is no good reason whatsoever to pass handles by &in reference. A signature such as "int32 getIndexOf(const IItem@ hItem)" should work correctly.

Advertisement

I've identified a bug in the script compiler when the function argument is IItem@ &in and it is passed on to another function. In this case the compiler is not correctly dereferencing the argument.

I'm working on the fix.

In the meantime you should be able to make it work without the &in, which as Sir Ementaler correctly mentioned, is not really necessary for @ arguments.

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

I've fixed the bug in revision 2347.

Regards,

Andreas

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

It would be good to have something like "reference equals" as the default for opEquals (like in C# for example). This would also allow to put an instance of any class to array without implementing opEquals.

Thanks for the suggestion. I'll keep it in mind for a possible future enhancement.

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

Hello Sir Ementaler!

That appears to be some sort of a side effect, possibly a bug, of passing the handle by non-const &in reference. There is no good reason whatsoever to pass handles by &in reference. A signature such as "int32 getIndexOf(const IItem@ hItem)" should work correctly.

Yes I agree on 100% that it's unnecessary to pass handles by &in reference.

But such signature is a part of ScriptArray addon API: when we create a variable of

type array<IItem@> the find method

(whose signature is int find(const T&in if_handle_then_const value) const)

will actually have the find(const IItem@ &in if_handle_then_const value) const signature.

It seems there is no any method to avoid such a situation in array<>.

So I just simulated this logic in my simple example above to show the problem.


Hello Andreas!

I've fixed the bug in revision 2347.

Regards,

Andreas

I recompiled the library and all works perfect!

Thank you very much!

Your support is really better than the "paid support" in some companies. :)

This topic is closed to new replies.

Advertisement