Creating C Closures From Lua Closures
Key topics
The quest to seamlessly integrate Lua closures with C callbacks has sparked a lively debate, with some commenters questioning the need for generating assembly code to achieve this goal. The author, publicdebates, explains that the challenge lies in creating C callbacks that work as native function pointers, particularly with Win32 APIs that lack a context/userdata parameter. While some suggest alternatives, such as returning a table or leveraging libffi, others point out the limitations of these approaches, including the need to automate the process for every callback type in the Windows API. As the discussion unfolds, it becomes clear that the problem is more nuanced than initially meets the eye, with various trade-offs and platform-specific considerations coming into play.
Snapshot generated from the HN discussion
Discussion Activity
Active discussionFirst comment
5d
Peak period
12
108-120h
Avg / period
5.7
Based on 17 loaded comments
Key moments
- 01Story posted
Dec 11, 2025 at 2:08 PM EST
28 days ago
Step 01 - 02First comment
Dec 16, 2025 at 2:43 AM EST
5d after posting
Step 02 - 03Peak activity
12 comments in 108-120h
Hottest window of the conversation
Step 03 - 04Latest activity
Dec 19, 2025 at 10:34 AM EST
20 days ago
Step 04
Generating AI Summary...
Analyzing up to 500 comments to identify key contributors and discussion patterns
Want the full context?
Jump to the original sources
Read the primary article or dive into the live Hacker News thread when you're ready.
Or, if you're worried about performance/memory, you could allocate a struct for `CALLBACK` to return as userdata, containing the function pointer and `findex`. If you made a little allocator for these it would be extremely fast.
I'm sure I'm missing things, but the solution you chose feels like the nuclear option.
This was probably posted in response to this other link from two days ago, which is about about JIT-compiling wndproc callbacks in particular; the comments discuss the “proper” way to do it, which is to use GWLP_USERDATA:
https://news.ycombinator.com/item?id=46259334
At least, that’s the proper way to do it if you control the entire application. But for what’s apparently a thin wrapper that exposes Win32 APIs directly to Lua, I can understand picking an approach that makes life easier for the Lua code author, even if it’s hackier under the hood. It also avoids the need to write custom behavior for each API.
GWLP_USERDATA should be the best option, though the API for setting it and setting the WNDPROC being separate looks error prone.
That said, I'm not sure that solution beats out this one. I'm using a linked list on top of an arena allocator in practice, which means allocations happen once every 0x10000 bytes. (A single C closure of mine takes up exactly 16 bytes, which includes the pointer to the next linked list node. I'm very happy with how it's designed.)
First, it would mean that all Lua objects would be allocated in memory that's potentially executable. That might not necessarily be more of a security issue than the app inherently allows, but at least it's wasteful.
Second, I'm not entirely sure it's a good idea to have C callbacks be collectable, which is why currently they aren't, and you have to free them manually via my winapi.freecallback function. This is part of the inherent issue in the fact that the Windows API has its own concept of lifetimes that are different than Lua's collection visibility. I would like to try to tie them together if possible one day, I'm just not entirely sure how yet.
https://news.ycombinator.com/item?id=46228597
https://news.ycombinator.com/item?id=46259334
Also talking about the Knuth boy/man test: https://news.ycombinator.com/item?id=46020151
Not a bad thing, but that really question if there is some active micro-
https://luajit.org/ext_ffi_semantics.html