It was my experience too. What does the C API do for one? I&#x27;ve always found it rather unhelpful, though relatively straightforward for simple bindings. (I don&#x27;t like to comment about anything more involved.) But, even once you&#x27;ve got your own wrappers in place for converting Lua userdata objects to pointers to your custom types, and whatever, your average Lua binding still looks like this:<p><pre><code>    1. Get arguments from stack one by one

    2. Call C function with arguments
    
    3. Push result(s) to stack one by one

    4. Return number of results
</code></pre>
(You can write your own system to automate all of this this - rather more straightforward in C++ than in C - but that is hardly evidence that the C API is especially useful.)<p>Suppose you have a function in lua, `f(x,y)&#x27; that you want to forward to your C function, `int f(int x,double y)&#x27;. You need to do something like this:<p><pre><code>    int lua_f(lua_State *L) {
        int x=luaL_checkinteger(L,1);
        double y=luaL_checknumber(L,2);
        int result=f(x,y);
        lua_pushinteger(L,result);
        return 1;
    }
</code></pre>
(It&#x27;s worth having a scrabble through to see what the luaL stuff is doing internally, because some of it is string-happier than you might like. luaL_checkudata seems particularly rude. But checkinteger and checknumber seem benign enough.)<p>If you don&#x27;t use a debugger, and you&#x27;re certain you&#x27;ll never need any logging or whatever, and you&#x27;re sure future you won&#x27;t mind having to split things all out when they are in the middle of something else and discover they need logging after all, you could do it maybe more like this:<p><pre><code>    lua_pushinteger(L,f(luaL_checkinteger(L,1),luaL_checknumber(L,2));
    return 1;
</code></pre>
But even that still doesn&#x27;t strike me as particularly convenient.