lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Mon, Jun 02, 2008 at 06:06:50PM +0900, YutakaUeno wrote:
> 
> This is a result of my experiment for an easyer API, tentatively named
> as EasyLua, as a simpler way to embed Lua into a C-program, not C++.
> While the formal C-API is just fine, but this is a subset for beginers.
> The main idea of my method is to minimize thinking about the lua-stack
> on accessing Lua data from a C-program.
> It was deviced after I was wondering if we can use following way to
> refer Lua values from a C language.
> 
>   int nframe_inlua   = el_num(el_var("nframe"));
>   char * title_inlua = el_str(el_var("title"));
> 
> Here, the function el_var() will keep the name of the global variable
> on the stack, then on calling el_num(), it invokes
> lua_gettable(L,GLOBALSINDEX) and calls lua_tonumber().

To make it even simpler I would suggest to hide el_val() function from
user. So one can write:
   int nframe_inlua = el_num("nframe");
   char * title_inlua = el_str("title");

> For writing a value into Lua, it might be following way.
> 
>   el_setnum(el_var("nframe"), 100);

Similarly for setting variable:
    el_setnum("nframe", 100);

> For these two ways for reading and writing, we just need to maintain
> the stack contents properly using the return value of el_var().
> Using two stack elements, table and index can be specified.
> So, I would like to access a field in a Lua table
> like following way. First, the table is assigned an integer
> handle, in this sample, number 2 is assigned.
> 
>   el_table(2,"user");
>   el_num(el_field(2,"uid");
>   el_setnum(el_field(2,"uid"),9601); /** user.uid=9601 **/

For setting fields in table I would suggest:
    el_table_setnum("user", "uid", 9601);
    el_table_setstring("user", "name", "my_own_name");

Similarly for fetching fields from table:
    int uid = el_table_num("user", "uid");
    char * name = el_table_string("user", "name");

> Is it simple enough for beginers?

I thing that introducing integer handle would unnecessary confuse
_beginner_ users. Users more experienced should anyway use
standard API.

> Since most of program in my work is a standalone program that will
> only use several of Lua variables, including a few tables.
> Probably there are discussions for this method, and improvements
> are needed. This method is less efficient as the formal API, but
> it is much more comprehensive. This EasyLua API does not
> provide full set of functionality yet.
> Again, this subset API is to lower the hardle for beginers.
> For those who understand the formal C-API of Lua, it will
> be better to use the formal one.

Yes, I guess some users that need only limited portion
of usability of embedded lua will agree to trade efficiency
for ease of use. But you should than emphasize very loudly and
very often in manual for your implementation that it is just
simplified and very reduced set of lua. I would think  very hard
if there should be implemented any more than this 8 functions:
    el_num
    el_setnum
    el_table_num
    el_table_setnum
    el_string
    el_setstring
    el_table_string
    el_table_setstring
Naturally you need to provide something like this too:
    el_luaopen() // create new lua state and assign it to
		 // global variable that all other functions refer to
    el_luaclose()  // close above created lua state
    el_loadfile("my_script.lua") // load and execute script file

And of course you need to handle errors in some graceful way in all
of your functions (if that is possible in general way). There are
two ways I can think of:
 - ignore all errors (not very good, I guess)
 - exit the application (not very user friendly)

If user need more functionality there should be strong warning
that it is needed to use standard API and not to mix easy_lua
API with standard one. If facilities provided with easy_lua
are enough for task under the hand than OK, if you need more
do not use easy_lua at all!

> Is there already such a method used by somebody?
> My implementation is uploaded on my site:
> http://www.cbrc.jp/~ueno/devzone/ezlua01.tgz
> 
> It is still experimental, but I would be happy if people test
> and examine. In this implementation, the name of global variables
> or filed name was saved in the Lua stack, and they are cleaned
> after a value is obtained. Calling Lua function is a bit tricky
> because the Lua stack have to be used for the argument and
> return values. EasyLua takes a table for return values.
> 
>   ip=el_var("print");
>   el_pushnum("something");	/** the same as official API **/
>   el_pushstr(10.0);
>   ir=el_call(ip);
>   el_num(el_index(ir,1)));      /** if return values exist **/

This is one example where I think that your proposed easy_lua API
does not bring anything simpler to user than there already is.
Normally it would be written (without error checking!) as:
  lua_getglobal(L, "my_func");
  lua_pushstring(L, "something");
  lua_pushnumber(L, 10.0);
  lua_pcall(L, 2, 1, 0);
  double num = lua_tonumber(L, -1);
It is basically line for line replacement and I do not think that
is of any benefit (on the other hand it can be confusing for beginner
in that way that it bring two alternative way to do the same thing:
one of which is official way and the other one that is no simpler
than first one.

If you want to simplify function call you should restrict yourself
only to most common cases. Something like this:
     double el_num_call_num(double arg);
     char * el_string_call_string(char * arg);
perhaps even:
     double el_num_call_string(char * arg);
     char * el_string_call_num(double arg);
or some other combinations that you find most needed. But do
not get carried and implement lot of combination (more than
one argument of different types, function that return more
than one value etc...)

Note that even accessors to table are crippled:
values stored and fetched can be only numbers and strings, not
booleans, function, tables ... Also keys are only string, not all
the other types (numbers are used very often for example).

For your proposed approach to function calling I have
some observations/questions:
- it seems you swapped arguments for el_pushnum and el_pushstr
- standard function print actually does not return any value
  (but you have covered that case with comment at last line
  so it is ok)
- in function el_index what is meaning of second argument?

> Any comments are welcome.
> ---
> Yutaka Ueno

Again to repeat myself. I think you should limit yourself to
implement only very small set of functions that will cover
most often used cases of storing and fetching values form
global variables and tables. If you will try to every feature
(or lot more than accessing variables and perhaps call to simple
functions) my belief is that it will be not easy API anymore. It
will be just different than the official one. And that will do
no good to anyone.

Misko