The Boston Diaries

The ongoing saga of a programmer who doesn't live in Boston, nor does he even like Boston, but yet named his weblog/journal “The Boston Diaries.”

Go figure.

Wednesday, March 04, 2015

Mimicking C APIs in Lua

Last Sunday, the latest announcement of luaposix lead me to state the following observation on the Lua mailing list:

From
Sean Conner <sean@conman.org>
To
Lua mailing list <lua-l@lists.lua.org>
Subject
Literal mimicking of C APIs in Lua (split from Re: [ANN] luaposix 33.3.0 released)
Date
Sat, 28 Feb 2015 23:16:51 -0500

This isn't about luaposix per se, but this is prompting this observation about Lua wrappers for C APIs: they tend to mimic it quite literally (to the point where I think I've said this before: if I wanted to code in C, I know where to find it).

I checked, and sure enough, the Lua wrapper around syslog() was what I expected (and had found in several other syslog() wrappers for Lua)—a very thin wrapper over syslog() leading to this in Lua:

syslog.syslog(syslog.LOG_WARNING,string.format("foobar %d is at %d capacity",fooid,foocap))

I seem to be the only one who make it easy to use syslog() in Lua:

syslog('warning',"foobar %d is at %d capcaity",fooid,foocap)

I went to the trouble of ma king the module itself callable (but you can still call syslog.log() if you want) and handle the call to string.format() be half of the caller because in 90% of the cases I call syslog(), I need formatted output.

It just struck me as odd that not many writers of C-based Lua modules bother to make it easy to use their modules and I was about the thought process behind it (or the lack of thought process). The best answer came from Gary Vaughan, author of luaposix:

From
"Gary V. Vaughan" <XXXXXXXXXXXXXXX>
To
Lua mailing list <lua-l@lists.lua.org>
Subject
Re: Literal mimicking of C APIs in Lua (split from Re: [ANN] luaposix 33.3.0 released)
Date
Sun, 1 Mar 2015 09:02:00 +0000

It's precisely because I don't want to code in C either that the low- level API of luaposix aspires to be as thin a wrapper for the C API as possible. It's easier, faster and less error-prone to write the Luaish API on top of the thin C wrappers in Lua than it is to write the fancy stuff in C.

Not only that, this leaves the door open to replace the C bindings with an FFI binding that the Luaish layer can equally sit on top of and ultimately shipping no C code at all in luaposix… as long as a dependency on LuaJIT and/or LuaFFI is an acceptable compromise. When the low-level C code implements the user- facing API, all of this is a lot more difficult.

He's got a good point—make the C layer as thin as possible:

static int syslog_syslog(lua_State *L)
{
  syslog(luaL_checkinteger(L,1),"%s",luaL_checkstring(L,2));
  return 0;
}

and leave the fancy stuff up to Lua:

local m_priority =
{
  emerg  = 0, emergency   = 0,
  alert  = 1,
  crit   = 2, critical    = 2,
  err    = 3, error       = 3,
  warn   = 4, warning     = 4,
  notice = 5,
  info   = 6, information = 6,
  debug  = 7
}

function syslog(priority,...)
  syslogcore.syslog(m_priority[priority],string.format(...))
end

But there is a flaw when he metions LuaJIT (and LuaFFI in general):

C declarations are not passed through a C pre-processor, yet. No pre- processor tokens are allowed, except for #pragma pack. Replace #define in existing C header files with enum, static const or typedef and/or pass the files through an external C pre-processor (once). Be careful not to include unneeded or redundant declarations from unrelated header files.

ffi.* API Functions

In the case of syslog(), it's not that big an issue—the levels are standardized so it's easy to supply the proper values, but it's different for a function like socket(). A thin C wrapper is trivial:

static int socket_socket(lua_State *L)
{
  lua_pushinteger(
    L,
    socket(
      luaL_checkinteger(L,1),
      luaL_checkinteger(L,2),
      luaL_checkinteger(L,3)
    )
  );
  lua_pushinteger(L,errno);
  return 2;
}

Not so easy is defining the values for those three parameters. The first is an arbitrary number defining the “family” the socket belongs to, ether IP, IPv6, Unix domain, etc. The second parameter further defines the socket type, whether it's a stream based socket, or you want actual packets. The last parameter can, in 99% of the cases, be 0, so we shall ignore it. In C, it's typically called like:

s = socket(AF_INET,SOCK_STREAM,0);

But the actual value of AF_INET may vary from operating system to operating system (they do—I checked a few systems to make sure) so it's not always as straightforward to skip C entirely when wrapping a C API with LuaJIT.

Overall though, the idea is sound and I do find it intriguing, but not enough to stop the approach I've been taking.


Mind blown

When you bite into a Thin Mint, you probably aren't wondering where it comes from. (The Girl Scouts, of course.) But wait, there are two bakers. And they make two very different Thin Mints: One is crunchier, more minty. The other is richer with a smooth chocolate coating.

Via Jeff Cuscutis at FaceGoogleMyBookPlusSpace, 6 Girl Scout cookies you thought you were getting but aren't - Los Angeles Times

Wait … what?

Obligatory Picture

[The future's so bright, I gotta wear shades]

Obligatory Contact Info

Obligatory Feeds

Obligatory Links

Obligatory Miscellaneous

You have my permission to link freely to any entry here. Go ahead, I won't bite. I promise.

The dates are the permanent links to that day's entries (or entry, if there is only one entry). The titles are the permanent links to that entry only. The format for the links are simple: Start with the base link for this site: https://boston.conman.org/, then add the date you are interested in, say 2000/08/01, so that would make the final URL:

https://boston.conman.org/2000/08/01

You can also specify the entire month by leaving off the day portion. You can even select an arbitrary portion of time.

You may also note subtle shading of the links and that's intentional: the “closer” the link is (relative to the page) the “brighter” it appears. It's an experiment in using color shading to denote the distance a link is from here. If you don't notice it, don't worry; it's not all that important.

It is assumed that every brand name, slogan, corporate name, symbol, design element, et cetera mentioned in these pages is a protected and/or trademarked entity, the sole property of its owner(s), and acknowledgement of this status is implied.

Copyright © 1999-2024 by Sean Conner. All Rights Reserved.