Advertisement

Parameter references

Started by August 24, 2005 05:49 PM
9 comments, last by WitchLord 19 years, 3 months ago
I'm a bit lost on registering C++ functions that take parameter references. I've tried references and handles, but neither seem to work. Consider the following C++ function:

template<class T>
static
void foo(T* arg)
{
  *arg = 55;
}
Granted, this example only works for certain types of T. But I am having trouble registering this function. I've tried the following:

bool my_register(asIScriptEngine* engine)
{
  if ( engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SRL, "void f(uint &out)", asFUNCTIONPR(foo<unsigned long>, (unsigned long *), void), asCALL_CDECL) < 0)
    return false;

  return true;
}
The call to RegisterGlobalBehaviour returns -10. I've looked into the code, and it fails because it says that references require a "in". So, I tried other cases:

"void f(uint &inout)"
"void f(uint @+)"
And both fail. The only call that registers successfully, but doesn't operate correctly is:

"void f(uint ∈)"
And it makes sense that this doesn't work (because of the evaulation and copy semantics). I know I'm likely overlooking something simple. My search of the forums and reading the documentation hasn't revealed a solution yet. So, how do I pass a parameter to a primitive type via a pointer?
The asBEHAVE_BIT_SRL (>>) operator requires two operands. Also, the script operators only allow ∈ references, so you shouldn't try to alter the values. The engine may in some cases send the reference to the actual variable, but in others it may be to a different variable so you may get unexpected results and difficult to find bugs, if you did what you're trying to do.

If you want to alter the value of the parameter reference, you must use a normal function that allows &out, and &inout.

The following works:

void func(int &v){   v = 55;}engine->RegisterGlobalFunction("void func(&out)" asFUNCTION(func), asCALL_CDECL);

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
Quote: Original post by WitchLord
The asBEHAVE_BIT_SRL (>>) operator requires two operands.

The above was a contrived example. I'm actually trying to get the input streams ported to the latest Angelscript version.
Quote: Original post by WitchLoard
Also, the script operators only allow ∈ references, so you shouldn't try to alter the values. The engine may in some cases send the reference to the actual variable, but in others it may be to a different variable so you may get unexpected results and difficult to find bugs, if you did what you're trying to do.

Indeed. So how do input streams work? The streams code is based on an older version of the Angelscript library, and in it I see the following:
template <class T>std::istream * ExtractOperator(std::istream * in, T * value){	*in >> *value;	return in;}

coupled with
RegisterBehavoir(engine, asBEHAVE_BIT_SRL, "instream & f(instream &, bool &)", ExtractOperator<bool>);

and the RegisterBehavoir() function is defined as:
template <class T>inline void RegisterBehavoir(asIScriptEngine * engine, asDWORD behaviour, const char * name, T func){	engine->RegisterObjectBehaviour(0, behaviour, name, asFunctionPtr(reinterpret_cast<void (*)()>(func)), asCALL_CDECL);}

So if the SRL operator only allows ∈ references, then how did the above code work? How can I register an input stream class and use the SRL operator as an extraction operator if I can only have ∈ references?
I wrote this long answer trying to give you a solution, but when I finished I realized that I had completely missed the point of the true problem. I was focusing on the actual stream object, but forgot about the value that is extracted from the stream.

There is really no easy solution to this problem at the moment. Since only ∈ references are allowed, there is no way you can have the operator change the value of the operands unless the operands use shared memory.

I need to change the way the library handles this. The library must be able to allow operators change the value of the operands for this to work.

I'll finish version 2.4.0 first, and after that I'll give this problem top priority. I was planning on changing the way parameter references work anyway, since I'm not quite satisfied with the current solution.

I hope that I will be able to find a solution to this. But I not 100% sure that it is possible, without breaking other restrictions that are needed to keep the library safe.

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

Could the stream be written to take a handle? It would then be possible for AngelScript to automatically create a handle to stack-based object and pass that to the function. Some sort of binding flag would have to be added to allow this conversion on specific functions, or the script could do the conversion-to-handle explicitly. Allowing it universally would probably cause problems.
This is a really a rather difficult problem that Suudy discovered.

Some of the problems that I'm facing:

1. I cannot keep pointers on the stack while evaluating expressions. It's possible that they become invalid before they are used again.

2. Argument expressions for output references are evaluated after the function call, because of number 1. A returned reference, for example, must be used before the output parameters are evaluated.

3. I must keep operator precedence and order of evaluation, e.g. for >> the left operand must be evaluated before the right operand. This goes against rule number 2, if I allow output references for operators.

Allowing object handles doesn't solve this, although it might help in some situations. Primitives for example cannot use object handles, and somehow wrapping them in an object that support handles isn't really a good solution. For example, how would I wrap an object property of a primitive type, or an element in an array?

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
I understand why the << operator can only accept in references, but I'm forced to wonder why the >> operator doesn't then only accept out references.

Quote: the script operators only allow ∈ references


Is this true for all operators? It would make sense if it were. Operator >> for streams is unigue in that it is the only operator that modifies it's right-hand side. Could it be a special case that is required to be registered with an out reference?
We decided on a workaround for the output parameter references. Rather than rely on the SRL operator, we just defined a template member function overloaded for all the types we are interested. We just don't get the pretty chaining.

For example, we defined:
template<class T>bool mystream::get(T* val){  _stream >> *val;}

Where _stream is the wrapped input stream. We registered them as overloaded functions, one for each type:
engine->RegisterObjectMethod("ifstream", "bool get(bool &out)", asMETHODPR(asCIScriptStream, get<bool>, (bool*), bool),  asCALL_THISCALL);engine->RegisterObjectMethod("ifstream", "bool get(uint &out)", asMETHODPR(asCIScriptStream, get<unsigned long>, (unsigned long*), bool),  asCALL_THISCALL);

etc, etc, for each type we want.

This works fine for now, and in the end, we will likely just add the extraction operator rather than remove these functions.

Thanks for generating and supporting such a fantastic piece of software! I can't say enough about how much we appreciate what you've done. Our end-users love the ability to script their testbenchs, and with the huge variety of add-ons (the preprocessor being our favorite!), we are all very thrilled.
Suudy:

I'm happy that you found a solution, even though it may not be exactly what you had in mind.

I'm also very happy that you enjoy the library so much. Please spread the word. [wink]

Deyja:

Quote: Original post by Deyja
I understand why the << operator can only accept in references, but I'm forced to wonder why the >> operator doesn't then only accept out references.

Quote: the script operators only allow ∈ references


Is this true for all operators? It would make sense if it were. Operator >> for streams is unigue in that it is the only operator that modifies it's right-hand side. Could it be a special case that is required to be registered with an out reference?


The problem is that all operators only support &in. To AngelScript there is no difference between any of the overloaded operators, except their token and the precedence, e.g. << and >> is treated the exact same way. If I allow >> to be registered with an &out operands, I should allow all operators to do that. I won't make a special case just to support streams.

None of the default operators modify the operands (this is true for C++ as well). I'm also not too fond of the C++ streams. This is why I forgot about the possibility that someone would want to register operators that change the value of the operands.

Maybe I can solve this case by implementing member operators. The left hand operand would then by default be changeable, and I would just have to worry about the right hand operand. I'll have to think about this some more.

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

Wouldn't the left hand side need to be changable already, to support ++ and += (etc)?

I understand why you don't want to make a special case. I hate them too. :D

This topic is closed to new replies.

Advertisement