Implicitly assign handle by overloading opImplConv operator

Started by
11 comments, last by Ali Gerami 6 years ago

Hi, I have modified CScriptAny a little and by overloading opCast and opImplConv I won't need .Retrieve method.

Everything is fine, objects and primitive types are retrieved successfully but when I try to assign a handle implicitly it fails completely.

Example:


obj@ myObject;
@myObject = myAny; // myAny is a valid any object

I tracked more and I found out that ref pointer (1st parameter) is NULL and typeID (2nd parameter) is set to that object type id ((typeID & asTYPEID_MASK_OBJECT) == true) and in typeID, asTYPEID_OBJHANDLE flag is not set! (However, this problem does not occur by using .Retrieve method or any method instead of implicitly assigning)

Also, I feel that opConv operator overloading fails, e.g. I want to have something like this: int(myAny); and it gives errors while compiling.

And by the way, what is opImplCast when opImplConv exists? When I try to register opImplCast I'm not able to assign my 'any' object (e.g. any myAny = 50;) (I have overloaded opAssign too, so no more .Store method)

Advertisement

opConv and opImplConv are used to allow type conversion. The difference is that the first requires an explicit conversion call, while the second tells the compiler that it can implicitly convert the type if possible. 

opCast and opImplCast are used to cast the reference to a different type but still refer to the same object. (normally used for class hierarchies or interfaces, etc)

You didn't show exactly how you modified the CScriptAny add-on so I cannot evaluate if you've done something wrong or not. I suggest taking a look at the dictionaryValue type (part of the dictionary add-on) it already does what you're planned to do. Compare it with what you've implemented.

 

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

Thanks for your reply.

Well, I looked and checked CScriptDictionary before and modified that too, but I tested with the original version this time.

And here is the error I get when I try to compile:

Quote

Can't implicitly convert from 'dictionaryValue' to 'Object@'.

Object is an object type of asOBJ_REF.

The script I used:


dictionary myDict = {{"myHandle", @myObject}}; // this line works, without the error line it's fine
Object@ myHandle;
@myHandle = myDict["myHandle"]; // this line gives the error

Edit: When I overload opImplConv in the original CScriptDictionary, the error line above will not be shown and the exact same problem I have in my modified 'any' object happens here too.

5Gecl5.png

Edit 2: Looks like opCast operator overload (@myHandle = cast<Object>(myDict["myHandle"])) works fine, just like .Get method but still implicit conv fails, why is that? Can't we implicitly/(it's more explicitly) assign/convert a handle?

Implicit cast should work the same way. It sounds like there might be a bug in the library. I'll look into it.

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

Which version of AngelScript are you using? I wasn't able to reproduce the problem in the latest WIP version.

To try to reproduce the problem you mentioned I did the following. 

1. Change RegisterScriptDictionary to register opImplCast instead of opCast:


    r = engine->RegisterObjectMethod("dictionaryValue", "void opImplCast(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 );

2. Wrote the following test case:
 


		engine = asCreateScriptEngine();
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		RegisterStdString(engine);
		RegisterScriptArray(engine, true);
		RegisterScriptDictionary(engine);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		mod = engine->GetModule("module", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"class Object {} \n");
		r = mod->Build();
		if (r < 0)
			TEST_FAILED;

		r = ExecuteString(engine,
			"dictionary dict = { { 'myHandle', Object() } }; \n"
			"Object @myHandle; \n"
			"@myHandle = dict['myHandle']; \n"
			"Object @myHandle2; \n"
			"@myHandle2 = cast<Object>(dict['myHandle']); \n"
			"assert( myHandle is myHandle2 ); \n"
			"assert( myHandle !is null ); \n", mod);
			
		if (r != asEXECUTION_FINISHED)
			TEST_FAILED;


		engine->ShutDownAndRelease();

Both the implicit cast and the explicit cast works the same way in my test.

 

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 was using the latest stable source code which didn't work and my own source code.

Now I tested with the WIP source code, compiled it and tested with the following exact code on a new project.

I checked, in the debugger call stack, Line 'assert(bAssertion);' throws an exception and guess what, assertion failed. The exact same bug. (I'm using latest Visual Studio and compiling with C++17, tried C++14 too, still the same)

Edit: I compiled AngelScript with 'AS_NO_THREADS' preprocessor definition, but I don't think that it's causing this.


void MessageCallback(const asSMessageInfo * msg)
{
    printf("msg: %s %i\n", msg->message, msg->row);
}

void Assert(bool bAssertion)
{
    assert(bAssertion);
}

int main()
{
    asIScriptEngine* engine = asCreateScriptEngine();
    engine->SetMessageCallback(asFUNCTION(MessageCallback), NULL, asCALL_CDECL);

    RegisterStdString(engine);
    RegisterScriptArray(engine, true);
    RegisterScriptDictionary(engine);
    engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_CDECL);

    asIScriptModule* mod = engine->GetModule("module", asGM_ALWAYS_CREATE);
    mod->AddScriptSection("test",
                          "class Object {} \n");
    int r = mod->Build();
    if (r < 0) assert(0);

    r = ExecuteString(engine,
                      R"ascode(dictionary dict = { { 'myHandle', Object() } };
                      Object @myHandle;
                      @myHandle = dict['myHandle'];
                      assert( myHandle !is null );)ascode", mod);

    if (r != asEXECUTION_FINISHED) assert(0);

    engine->ShutDownAndRelease();

    return 0;
}

I use Visual Studio 2015, I believe it only supports up to C++11. 

But I doubt it is the newer C++ version that causes the problem for you. After all, AngelScript works even without C++11 on older compilers too.

I've tried several options; 64bit, 32bit, with or without AS_NO_THREADS, debug and release mode, and so far I haven't been able to reproduce this error.

 

I did identify another problem while doing this related to the opImplCast with the variable type. The compiler would try to use this even for non reference types, and cause an assert failure (in debug mode) or crash (in release mode). I've fixed this in revision 2491. You will need this fix too, but unfortunately it doesn't fix the problem you've reported.

 

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 did notice that bug before and I actually reported it:

But I noticed by removing opImplCast operator overload, my problem solved so I thought it's not a bug.

However, I installed VS 2015, with the latest revision, registered opImplConv in dictionaryValue,

1. In test_feature project (msvc test as) this happens:

egYmUS.png

9JplBd.png

VObp8o.png

2. test_castop.cpp Line 184 fails as well.

3. My old bug still exists, even with VS 2015, latest revision and THE EXACT SAME SOURCE CODE you posted in here in the exact same test_feature msvc project.

kDOnvs.png

w5PPVe.png

 

---------------------

I took these screenshots, if you want me to take a video, downloading the actual latest WIP source code version, compiling it with VS 2015, add your code in msvc test as project and compile & test it, just do tell, if you want to remotely connect to my computer and see for yourself (or do it yourself), just do tell!

The assert failure you got now is because of this "However, I installed VS 2015, with the latest revision, registered opImplConv in dictionaryValue,"

When doing this you just added the opImplConv, right? But didn't remove the opConv? There is no use to have both of these.

(sure the library should be handling the situation better, but that is not the original problem you're facing.).

 

I'll try the latest MSVC. Though I find it hard to believe this is the reason for the bug you found, I cannot see anything else that you're doing differently from me. 

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 latest assert failure in revision 2492, so now objects can have both opImplConv and opConv (and also opImplCast and opCast).

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