🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Plugging away at the upgrade

Started by
4 comments, last by WitchLord 18 years, 11 months ago
I've actually got it working. Wasn't nearly as much work as I feared. Unfortunatly, I'm getting a lot of 'warning: argument will be evaluated twice'. And the occasional 'warning: Argument cannot be assigned. Output will be discarded'. I'm worried about that last one. The line generating the warning is 'DestroyObject(GetActiveObject())'. DestroyObject is declared 'void DestroyObject(Object& inout)'. GetActiveObject is declared 'Object GetActiveObject()'. Object is a smart pointer type. DestroyObject not only destroys the object, but sets the pointer to it to 0. It's kind of important that the new value of the object is propogated back to the call site, even if it's rather pointless in this case. What am I doing wrong? Is the second warning because it's treating the returned object as a const? And how can I keep it from evaluating GetActiveObject() twice?
Advertisement
From what WL says, &inout creates two objects, which is why it makes the call to your function twice i believe.
That doesn't mean it should be evaluated twice. It should be evaluated to the temporary, then the second should be copy-constructed from it.
It's not quite that simple.

The argument has to be evaluated twice, once to determine the value that is passed to the function, and yet another time to determine the final destination of the returned value. This is necessary because there is no way the final destination can be guaranteed to be valid when the function returns, if it is evaluated before the call. It's not very common that it will not be valid, but it is quite easy to think of cases where it won't be.

I know it is not a beautiful solution, but it is the best I could do. I seriously though of not allowing &inout althogether, but then I would break compatibility with some C++ functions.

If I was not aiming to make a safe scripting library I wouldn't have bothered with this at all. But since a scripting library should not allow the scripts to crash the application under any circumstances, I have no choice than to do it like this.

The compiler will not warn about evaluating the expression twice, if the expression is simple, e.g. a direct variable. It only warns when values are being altered in the expression (e.g. ++) or some function calls are involved, because it cannot know what is going on in those functions.

The warning that the argument cannot be assigned happens because the argument is not a valid lvalue. In your case GetActiveObject() creates a temporary object, and these are not valid lvalues. If the function instead returned a reference to the object, then it would be ok.

If you don't want the expression to be evaluated twice, you'll have to go with another solution than &inout. Perhaps you can implement support for object handles for your smart pointers? It ought to be a simple task, since the smart pointer probably has a reference counter already. Your DestroyObject() function would then receive a pointer to the true object, and could alter it as it sees fit.

By the way, you say that DestroyObject() destroys the object and sets the pointer to 0. But how does it guarantee that no other pointers are stored elsewhere in the application/script?



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

Quote: By the way, you say that DestroyObject() destroys the object and sets the pointer to 0. But how does it guarantee that no other pointers are stored elsewhere in the application/script?


It doesn't. But the object isn't actually destroyed; it's just given a flag which tells the mud engine it can recycle the object. I could just not modify the parameter at all. All application functions are no-ops if given 'recycled' objects. Making GetActiveObject return a reference would be a bad idea; it would allow scripts to change the active object.

Quote: This is necessary because there is no way the final destination can be guaranteed to be valid when the function returns

References in C++ are just pointers with slightly different semantics, and are passed exactly the same way. I can think of only one case where this can be fatal off the top of my head; if an application function deletes memory. I guess I'm just of the school of thought that says if you write it, and it blows up in your face, you got what you deserved.

Might I also suggest that the & be optional? Since you must have in/out anyway, why do we need the &? Alternativly, a plain & can default to inout. Also, since in effectivly just means by value anyway, why bother?
Quote:
References in C++ are just pointers with slightly different semantics, and are passed exactly the same way.


Exactly, and this is why I have to be so careful when passing references around in the scripting library. The references are not protected in anyway by C++, so I must protect them in the library.

Quote:
I can think of only one case where this can be fatal off the top of my head; if an application function deletes memory.


Correct. If references where only passed to application functions I wouldn't worry so much, but references can be passed to script functions as well, so I have to make it work the same way for both.

Quote:
I guess I'm just of the school of thought that says if you write it, and it blows up in your face, you got what you deserved.


This would work in a closed system. But in a scripted system the users are free to alter the scripts and even send them to each other. Most script writers are not very experienced programmers and may crash the application by accident, others may be experienced programmers but of bad faith and consiously write scripts to crash the application or worse. Do you want to be the one who opens up the door for hackers to enter your users' systems?

Quote:
Might I also suggest that the & be optional? Since you must have in/out anyway, why do we need the &? Alternativly, a plain & can default to inout. Also, since in effectivly just means by value anyway, why bother?


I choose to require both & and in/out for consistency. Having inout as default is not a good idea since it causes these problems that you yourself encountered with arguments being evaluated twice.

If I can find a way to improve this design I will. You can be sure of that.

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

This topic is closed to new replies.

Advertisement