lua-users home
lua-l archive

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


On Sun, 14 Nov 2021 at 04:09, Benjamin Riggs
<riggs@entropicengineering.com> wrote:
>
> I'm new to Lua and using it to run user-supplied business logic on an embedded system. The API I would like is for chunks to be loaded and run with each chunk leaving a function (with a closure) on the stack. This returned function will then be called periodically and will update state values. I'm trying to avoid requiring user code to use a designated name and trying to minimize the boilerplate of registering or assigning the function.
>
> Is there an elegant pattern that enables what I want?

I see two ways to do it:

1: the chunk is a function
as you probably know, the result of loading a Lua source file, either
with `load()` or `loadfile()` from Lua or `lua_load()`,
`luaL_loadbuffer()`, or `luaL_loadfile()` from C, is a function in the
stack.  So, if you just write your code straight in a file, _without_
wrapping with `function()...end`, it will produce a function that you
can call repeatedly.

there are some limitations with this:

1.1: no named parameters:  obviously, without a `function(...)` at the
beginning, you don't have named parameters, but you can still call it
with any number of arguments if you wish.  to give a name in the user
function, just start with `arg1, arg2, argxxxx = ...`  (the dots at
the end are the trick, it's not me trying to say "put something here",
actually write three dots)

1.2: no upvalues, unless your system provides some.  but that limits
flexibility for the end user

1.3: no "load time" for the user.  unless there's some contract that
the function is called with some parameter indicating it's just been
loaded, or use some upvalue to keep a count... neither is a nice way.


2. return the function

just end the user's file with a `return ffff` statement, where `fff`
is a function.  Either it was a `local function myfunc () .... end`
and then `return myfunc`, or directly like `return function() ...
end`.   for this to work, the system must first load the file as a
chunk, then call the chunk and the returned function will be found in
the stack.

any Lua code "outside" the function would be executed at "load time"
(on that first call, just after loading the chunk), so it can perform
any required initialization, and define any wanted upvalues (so the
returned function is a full featured closure).

the only limitation here is about the possibility of wanting more than
one function on a single user file.  for example, to share upvalues.
The easiest way to "extend" this would be to return a table instead of
a function.  which is exactly the same as defining a Lua module, that
can be loaded with `require`.

Of course, you could return any object with a `__call()` metamethod,
so it looks like a function and can be called normally, but keeps more
state besides upvalues, or could return other functions or values as
"fields", (either because it's actually a table, or by adding an
`__index`).


In short, if you're absolutely, positively sure that you won't require
multiple functions in the same file, just ask the user to return the
function at the end of the file.  Otherwise, ask for a small module.

-- 
Javier