LUA <--> C++ question

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

LUA <--> C++ question

Christophe Gimenez
Hello,

I would like to enable communication between LUA and C++ classes. I don't 
want to use "tolua" or any other tool.

Considere the following code, do you think these is a good way (or almost 
quite right) or do you think I was lucky not to have test.exe crashing ?
Is there a way to simplify the whole operation ?

Thanks a lot !!

-------------------------- test.cpp

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

extern "C"
{
	#include "lua.h"
	#include "luadebug.h"
	#include "lualib.h"
}

class myObject
{
	double	aProperty;

public:

	void setProperty(double pParam);
	double getProperty();
};

double myObject::getProperty()
{
	return aProperty;
}

void myObject::setProperty(double pParam)
{
	aProperty=pParam;
	printf("Inside setProperty\n");
}

myObject *global_Object;

void createNewObject(void)
{
	myObject *temp;
	temp = new(myObject);
	lua_pushuserdata(temp);
	global_Object = temp; // Why using temp ? just to see
}

void setObjectProperty(void)
{
	lua_Object params;

	params=lua_getparam(1);

	((myObject*)(lua_getuserdata(params)))->setProperty(lua_getnumber(lua_g  
etparam(2)));
}

int main (int argc, char *argv[])
{
	lua_open();
	lua_register("createNewObject",&createNewObject);
	lua_register("setObjectProperty",&setObjectProperty);
	lua_dofile("test.lua");

	printf("%f\n",global_Object->getProperty());

	lua_close();

	delete global_Object;
	return 0;
}

-------------------------- test.lua

aPrettyCube = createNewObject();

setProperty(aPrettyCube,123);

Reply | Threaded
Open this post in threaded view
|

Re: LUA <--> C++ question

Erik Hougaard
Christophe Gimenez wrote:
> 
> Hello,
> Considere the following code, do you think these is a good way (or almost
> quite right) or do you think I was lucky not to have test.exe crashing ?
> Is there a way to simplify the whole operation ?
> void setObjectProperty(void)
> {
>         lua_Object params;
> 
>         params=lua_getparam(1);
> 
>         ((myObject*)(lua_getuserdata(params)))->setProperty(lua_getnumber(lua_g
> etparam(2)));
> }

You need to use tags.. A tag can asure you that parameter 1 is of type
myObject* otherwise your code will crash if setProperty is called with a
bogus value as parameter 1. So create a tag and assign that tag to the
value you are pushing in createNewObject and test that parameter 1 must
be of that tag type in setProperty.

/Erik

Reply | Threaded
Open this post in threaded view
|

RE: LUA <--> C++ question

Ashley Fryer-2
In reply to this post by Christophe Gimenez
> I would like to enable communication between LUA and C++ classes. I don't
> want to use "tolua" or any other tool.
>
> Considere the following code, do you think these is a good way (or almost
> quite right) or do you think I was lucky not to have test.exe crashing ?
> Is there a way to simplify the whole operation ?

I use a similar approach in my code.  If you plan to use polymorphism, I
suggest you implement a common base class for all of your lua-enabled C++
classes.  Then make sure you always cast to the base class before
lua_pushuserdata.

Example:

class Scripted {};
class MyFoo : public Scripted {};

...

MyFoo my_foo;
lua_pushuserdata( static_cast< Scripted * >( & my_foo ) );

...

This also makes it possible to use dynamic_cast when you're going in the
other direction:

Scripted * my_scripted = (Scripted*)lua_getuserdata(lua_getparam(1));
MyFoo * my_foo = dynamic_cast< MyFoo * >( my_scripted );
if( my_foo )
{
// yes, we really have a MyFoo object...
}

These techniques will help you avoid some subtle bugs resulting from casts,
especially if any of your classes use multiple inheritance.

Other possibilities... you could implement a class with overloaded insertion
operators as syntactic sugar for the lua_pushXXX functions.  Then you could
do this:

LuaStack() << my_num << my_string;

Instead of:

lua_pushnumber( my_num );
lua_pushstring( my_string );


ashley



Reply | Threaded
Open this post in threaded view
|

RE: LUA <--> C++ question

Vincent Penquerc'h-2
[examples on casting snipped]
> These techniques will help you avoid some subtle bugs resulting 
> from casts,
> especially if any of your classes use multiple inheritance.

Could you elaborate a little on what subtle bugs not casting could
introduce please ?
I am using the same approach (I have a base class defining virtuals
for Lua access) but do not use these casts. And a few (not much) of
my such classes use multiple inheritance (but no more than 2 bases).
It works perfectly for the moment, but then it's still in its infancy.
I'd be interested in knowing what I could fall into at next step :)

-- 
Vincent Penquerc'h

Reply | Threaded
Open this post in threaded view
|

RE: LUA <--> C++ question

Christophe Gimenez
In reply to this post by Christophe Gimenez
As I said in a previous message (and I am really sorry for that) I still have NO IDEA of what "tags" are ?

So, when so say "So create a tag and assign that tag to the value you are pushing in createNewObject and test that parameter 1 must
be of that tag type in setProperty." what do it implies ?

Of course I don't understand lua_newtag, lua_settag, and so on...

BTW is there somewhere a collection of LUA source examples ? 

Thanks



-----Message d'origine-----
De:	Erik Hougaard [SMTP:[hidden email]]
Date:	mercredi 15 mars 2000 15:43
A:	Multiple recipients of list
Objet:	Re: LUA <--> C++ question

As I said in a previous message (and I am really sorry for that) I still have NO IDEA of what "tags" are ?

So, when so say "So create a tag and assign that tag to the value you are pushing in createNewObject and test that parameter 1 must
be of that tag type in setProperty." what do it implies ?

Of course I don't understand lua_newtag, lua_settag, and so on...

BTW is there somewhere a collection of LUA source examples ? 

Thanks


Christophe Gimenez wrote:
> 
> Hello,
> Considere the following code, do you think these is a good way (or almost
> quite right) or do you think I was lucky not to have test.exe crashing ?
> Is there a way to simplify the whole operation ?
> void setObjectProperty(void)
> {
>         lua_Object params;
> 
>         params=lua_getparam(1);
> 
>         ((myObject*)(lua_getuserdata(params)))->setProperty(lua_getnumber(lua_g
> etparam(2)));
> }

You need to use tags.. A tag can asure you that parameter 1 is of type
myObject* otherwise your code will crash if setProperty is called with a
bogus value as parameter 1. So create a tag and assign that tag to the
value you are pushing in createNewObject and test that parameter 1 must
be of that tag type in setProperty.

/Erik

Reply | Threaded
Open this post in threaded view
|

Re: LUA <--> C++ question

Erik Hougaard
Christophe Gimenez wrote:
> 
> As I said in a previous message (and I am really sorry for that) I still have NO IDEA of what "tags" are ?
> 

How to Tag
----------

1. Create a global variable in your c/c++ program called MyObjectTag
2. Assign that with "MyObjectTag = lua_newtag()"
3. When pushing use "lua_pushusertag(pointer,MyObjectTag)"
4. When using test the lua_Object with "lua_tag(Object) == MyObjectTag"
to see if thats equal to MyObjectTag.

Thats it!

/Erik

Reply | Threaded
Open this post in threaded view
|

RE: LUA <--> C++ question

Ashley Fryer-2
In reply to this post by Vincent Penquerc'h-2
> From: Vincent Penquerc'h
>
> Could you elaborate a little on what subtle bugs not casting could
> introduce please ?

Sure.

#include <iostream.h>
class Base1 { public: int b1; };
class Base2 { public: int b2; };
class Derived : public Base1, public Base2 {};
void main( void )
    {
    Derived derived;
    void * pDerived = & derived;
    void * pBase1 = ( Base1 * ) & derived;
    void * pBase2 = ( Base2 * ) & derived;
    cout << pDerived << endl << pBase1 << endl << pBase2 << endl;
    }

On my system, this outputs:

0x0012FF6C
0x0012FF6C
0x0012FF70

Note that pBase2 != pDerived.  Therefore, if you do this:

lua_pushuserdata( & derived );

The value of the userdata is 0x0012FF6C.  If your lua script passes that
value back, and you cast it directly to Base2:

Base2 * pBase2 = ( Base2 * ) lua_getuserdata(lua_getparam(1));

pBase2 == 0x0012FF6C, when it should == 0x0012FF70.  Your code would crash.

A similar problem occurs if you do this:

Base2 * pBase2 = & derived;
lua_pushuserdata( pBase2 );

...

Derived * pDerived = (Derived *) lua_getuserdata(lua_getparam(1));

In this case, pDerived == 0x12FF70 when it should == 0x12FF6C.

The way to avoid both problems is to always perform an explicit cast to a
common base class when you push userdata, and always cast back to that base
class when you recover the userdata.

Regards,
ashley


Reply | Threaded
Open this post in threaded view
|

RE: LUA <--> C++ question

Vincent Penquerc'h-2
> #include <iostream.h>
> class Base1 { public: int b1; };
> class Base2 { public: int b2; };
> class Derived : public Base1, public Base2 {};
> void main( void )
>     {
>     Derived derived;
>     void * pDerived = & derived;
>     void * pBase1 = ( Base1 * ) & derived;
>     void * pBase2 = ( Base2 * ) & derived;
>     cout << pDerived << endl << pBase1 << endl << pBase2 << endl;
>     }
> 
> On my system, this outputs:
> 
> 0x0012FF6C
> 0x0012FF6C
> 0x0012FF70

Nicely done. Thanks a lot Ashley, I'd never thought of that. I guess my
classes inherit all inherit in the right order :)
I'll check that when I'm back home.

-- 
Vincent Penquerc'h