Overriding assignment of value in Lua - c

I am using Lua v5.2.2 within a C application (embedded environment/MCU).
I need to expose some "parameters" in Lua, that for reading and writing you need to directly access the hardware (thus a C call is needed). I am looking however for other means to implement this than using plain old getters and setters.
I am mostly exploring the meta-programming power of Lua, but also I believe I can create a simpler interface for the user.
What I want to achieve is behaviour like the following:
my_param = createParameter{name="hw_param1", type="number", min=0, max=100}
my_param = 5
result = my_param + 3
On the first line a new parameter is created. This is a call towards a C function. Userdata is pushed to stack with a properly initialized struct. The hardware is also initialized as needed. A new table is returned.
On the second line an assignment is done to the parameter object. I want this to call a C function with a single argument (that of the assignment), so the value can be stored to the hardware registers.
On the third line the parameter is read. I again need a call towards a C function that will get the value of the parameter from the hardware registers, and that will return the result.
Note that the actual value of this parameter may change outside the scope of Lua, so reading the value once during initialization is not correct. The C function must be called each time to get the actual value. Similarly writing to the value must cause an immediate write to the hardware.
How can I accomplish this? Specifically can I alter the metatable of the parameter to achieve lines 2 and 3? (I am aware of how to implement line 1).
Also is it necessary to return a table from the constructor? May I, for example, return a primitive Lua type (e.g. a number) that will behave like above?

Yes, you can modify the metatable metamethods.
Line 2 would completely change the variable's value that it holds.
However, if you were to set a field in the parameter object like: my_param.x = n, the __newindex metamethod would get invoked; which you could overwrite the metamethod to behave as you would like. In your case you would make it set the parameter's field and update it with a C function call.
Regarding line 3, same principle applies, instead this time you would just use the __add metamethod, and manipulate the object when __add is invoked.
http://lua-users.org/wiki/MetamethodsTutorial

This isn't exactly what you're asking for, but it's close:
function createParameter(t)
param = {}
param.data = t
backingTable = {}
metatable = {}
function metatable.__index(t, k)
-- You can intercept the value here if you
-- want and pass it on to your C fuction.
return backingTable[k]
end
function metatable.__newindex(t, k, v)
-- You can intercept the value here if you
-- want and pass it on to your C fuction.
backingTable[k] = v
end
setmetatable(param, metatable)
return param
end
--------------------------------------------------------
my_param = createParameter{name="hw_param1", type="number", min=0, max=100}
my_param.value = 5
result = my_param.value + 3
print(result) -- prints 8
print(my_param.data.name) -- prints hw_param1
You might be able to do something tricky by assigning a metatable to the global table _G, but I think that would be kind of tricky to get set up right and could lead to unexpected outcomes.
Edit:
If you really hate having to have a level of indirection, and you really want to be able to set it directly, here's how you can do it by setting the global table.
globalMetatable = {}
globalParamNames = {}
globalParams = {}
function globalMetatable.__index(t, k)
if globalParamNames[k] then
-- You can intercept the value here if you
-- want and pass it on to your C fuction.
print("Read from param " .. k)
return globalParams[k]
else
rawget(_G, k)
end
end
function globalMetatable.__newindex(t, k, v)
if globalParamNames[k] then
-- You can intercept the value here if you
-- want and pass it on to your C fuction.
print("Wrote to param " .. k)
globalParams[k] = v
else
rawset(_G, k, v)
end
end
setmetatable(_G, globalMetatable)
function createParameter(t)
globalParamNames[t.varname] = true
end
--------------------------------------------------------
createParameter{varname="my_param", name="hw_param1", type="number", min=0, max=100}
my_param = 5
result = my_param + 3
print(result) -- prints 8
print(my_param) -- prints 5

Related

Lua How iterators and for loops are work, what is it?

How does it work and why does the loop return values for k, v vars in order?
Why if I just call the next() function many times it does not return the same result as in the loop?
Where does the for loop get the values for the second argument of the next() function?
I don't understand how it works
local t = {'a', 'b', 'c'}
-- prints 1 a, 2 b, 3 c
for k, v in next, t, nil do
print(k, v)
end
print()
print(next(t)) -- 1 a
print(next(t)) -- why not 2 b?
print(next(t)) -- why not 3 c?
I don't understand much there https://www.lua.org/pil/7.html, I asked a question. How it works in lua - iterators, for loops, closures
next is a stateless iterator. That is, next is a pure function - its return values are determined only by its inputs (the invariant state: the table & the loop control variable: the key)
This explains why
print(next(t)) -- 1 a
print(next(t)) -- why not 2 b?
print(next(t)) -- why not 3 c?
must print 1 a three times: Each time, you call next with the table as first (and nothing as second argument). If the second argument to next is nil or nothing, next returns the first key-value pair of the given table. To get the next k-v-pair, you need to pass that key to next: next(t, 1) may give you 2 b. To fix your subsequent calls to next, you need to always pass the last key to get the next k-v-pair:
local k, v = next(t)
print(k, v) -- 1st entry
k, v = next(t, k)
print(next(t, k)) -- 2nd entry
k, v = next(t, k)
print(next(t, k)) -- 3rd entry
note that it is not guaranteed that next traverses the list part of a table in order (although all implementations do it this way)
As outlined in the PIL chapter 7.2, a for-loop is just syntactic sugar to iterate over such an iterator (for the sake of simplicity, we assume every iterator returns two values like next):
for k, v in next, t, nil do
print(k, v)
end
is equivalent to
local iterator_func, invariant_state, control_var = next, t, nil
while true do
local k, v = iterator_func(invariant_state, control_var)
if k == nil then break end
print(k, v)
control_var = k
end
pairs(t) is just even more sugar for next, t, nil (which may also be written as next, t). You can trivially implement pairs yourself as function pairs() return next, t, nil end. ipairs works similarly, except it doesn't use next but an "inext" iterator which only considers integer keys (and guarantees inorder traversal).
Stateful iterators on the other hand usually have a hidden state (usually upvalues of a closure). Every call to the iterator function changes the hidden state; the invariant state and loop control variable usually is not needed at all (and ignored entirely). These iterators behave as you would expect. We can write a stateful pairs (that is, a pairs which always returns a closure remembering the current position of the "cursor" in the table) as follows by making the current key an upvalue:
function stateful_pairs(t)
local key
-- This is the iterator function: Note how we may take no params
-- since we have everything as an upvalue already
return function()
local value
key, value = next(t, key)
return key, value
end
end
this now works the way you expected in your example, because the closure returned by this pairs remembers its state in upvalues:
local stateful_next = stateful_pairs(t)
print(stateful_next(t)) -- 1 a
print(stateful_next(t)) -- 2 b
print(stateful_next(t)) -- 3 c
and you can still use this in a for-loop. For stateful iterators without parameters, a for loop is just syntactic sugar for calling a function until it returns nil:
for k, v in stateful_pairs(t) do
print(k, v)
end
Lua has a few stateful iterators such as io.lines or string.gmatch in its standard library; making them stateless would require a very ugly loop control variable & invariant state.

Modifying Lua arguments in C function

A Lua script is using one of my C defined functions as bellow:
function lua_func()
local var = 5
-- Do some stuff here, possibly using var.
c_func(var)
-- Do other stuff here, that must not use var.
end
This C function takes an argument that the caller has created and does what it needs.
This argument to the C function must be of single-use, i.e. after the C function has used it, I don't want it to be accessible any more to the rest of the Lua script.
I am looking for a way for the C function to "consume" this argument. To use it, and then set it to nil, so it is no longer usable.
Is this possible, and if so how?
Variant 1:
function lua_func()
do
local var = 5
-- Do some stuff here, possibly using var.
c_func(var)
end
-- Do other stuff here, that must not use var.
end
Variant 2:
function lua_func()
local var_container = {5}
-- Do some stuff here, possibly using var.
c_func(var_container) -- it assigns nil to var_container[1] before exit
-- Do other stuff here, that must not use var.
end
Variant 3:
function lua_func()
local var = 5
local destructor = function() var = nil end
-- Do some stuff here, possibly using var.
c_func(var, destructor) -- it invokes destructor() before exit
-- Do other stuff here, that must not use var.
end

Looping over array values in Lua

I have a variable as follows
local armies = {
[1] = "ARMY_1",
[2] = "ARMY_3",
[3] = "ARMY_6",
[4] = "ARMY_7",
}
Now I want to do an action for each value. What is the best way to loop over the values? The typical thing I'm finding on the internet is this:
for i, armyName in pairs(armies) do
doStuffWithArmyName(armyName)
end
I don't like that as it results in an unused variable i. The following approach avoids that and is what I am currently using:
for i in pairs(armies) do
doStuffWithArmyName(armies[i])
end
However this is still not as readable and simple as I'd like, since this is iterating over the keys and then getting the value using the key (rather imperatively). Another boon I have with both approaches is that pairs is needed. The value being looped over here is one I have control over, and I'd prefer that it can be looped over as easily as possible.
Is there a better way to do such a loop if I only care about the values? Is there a way to address the concerns I listed?
I'm using Lua 5.0 (and am quite new to the language)
The idiomatic way to iterate over an array is:
for _, armyName in ipairs(armies) do
doStuffWithArmyName(armyName)
end
Note that:
Use ipairs over pairs for arrays
If the key isn't what you are interested, use _ as placeholder.
If, for some reason, that _ placeholder still concerns you, make your own iterator. Programming in Lua provides it as an example:
function values(t)
local i = 0
return function() i = i + 1; return t[i] end
end
Usage:
for v in values(armies) do
print(v)
end

Defining Table or Array name as name from Previously Defined String in Matlab

So I would like to optimize my code such that I can look through an array such as
{'one','two','three'}
and create corresponding variables defined as tables or arrays
such as
one = table()
two = table()
three = table()
I am aware of the eval function however I would like to use this function in a loop s.t I allocate values to the new variable right after i create it
If I am understanding your question properly, given a cell array consisting only of strings, you wish to create variables in your workspace where each variable is declared as a string using the names from this cell array.
You could use eval, but I'm going to recommend something other than eval. eval should be avoided and instead of iterating those reasons, you can read Loren Shure's article on eval.
In any case, I would recommend you place these variables as dynamic fields inside a structure instead. Do something like this:
s = struct()
strs = {'one', 'two', 'three'};
for idx = 1 : numel(strs)
s.(strs{idx}) = table();
end
In this case, s would be a structure, and you can access the variable by the dot operator. In this case, you can access the corresponding variables by:
d = s.one; %// or
d2 = s.two; %// or
d3 = s.three;
If you want to place this into a function per se, you can place this into a function like so:
function [s] = createVariables(strs)
s = struct();
for idx = 1 : numel(strs)
s.(strs{idx}) = table();
end
This function will take in a cell array of strings, and outputs a structure that contains fields that correspond to the cell array of strings you put in. As such, you'd call it like so:
strs = {'one', 'two', 'three'};
s = createVariables(strs);
However, if you really really... I mean really... want to use eval, you can create your workspace variables like so:
strs = {'one', 'two', 'three'};
for idx = 1 : numel(strs)
eval([strs{idx} ' = table();']);
end
To place this into a function, do:
function [] = createVariables(strs)
for idx = 1 : numel(strs)
eval([strs{idx} ' = table();']);
end
However, be warned that if you run the function above, these variables will only be defined in the scope that the function was run in. You will not see these variables when the function exits. If you want to run a function so that the variables get defined in the workspace after you run the function, then eval is not the right solution for you. You should thus stick with the dynamic field approach that I talked about at the beginning of this post.
In any case, this will create one, two and three as workspace variables that are initialized to empty tables. However, I will argue with you that the first line of code is easier to read than the second piece of code, which is one of the main arguing points as to why eval should be avoided. If you stare at the second piece of code long enough, then you can certainly see what we're trying to achieve, but if you read the first piece of code, you can ascertain its purpose more clearly.

Looking out of bounds in a 2D Lua table

I sometimes make small games in Lua, and often have to implement a 2D array as a grid or a board. When I want to check the cells surrounding a particular cell I usually give the 2D array a metatable so that when grid[outOfBoundsNum] is indexed it returns an empty table instead of an error:
setmetatable(grid, {
__index =
function(t, key)
if not table[key] then
return {}
else
return table[key]
end
end})
So when grid[outOfBoundsNum][anything] is called, it returns nil. Then, to check surrounding cells I do something like this :
for k, v in ipairs(neighbours) do
local cell = grid[v[1][v[2]]
if cell then -- check if this is actually within the 2D array
if cell == 1 then
-- do something
elseif cell == 2 then
-- do something else
...
end
end
This works, but it seems awkward to me. Is there a nicer or better way of doing it?
You don't need the metatable.
for k, v in ipairs(neighbours) do
local cell = grid[v[1]] and grid[v[1]][v[2]]
if cell == 1 then
-- do something
elseif cell == 2 then
-- do something else
...
end
end
Should do the job. It is a relatively common lua idiom to use logical and and or in expressions to act like the ternary operator in C.
So this line is equivalent to:
local cell = nil
if grid[v[1]]~=nil then
cell = grid[v[1]][v[2]]
end
You could write a forEachNeighbor() function which would take the grid, a position and a function and then call it with each existing neighborfield, i.e. encapsule the loop and the outer if in your second snippet in a function, you would use like:
forEachNeighbor(grid, position, function(cell)
if cell == 1 then
-- do something
elseif cell == 2 then
-- do something else
...
end)
Also, you could provide an at() function which would take a grid position as one parameter and return the corresponding field or nil, so that grid[v[1]][v[2]] becomes at(grid, v). This could also be implemented in addition to or instead of the __index metamethod.
For the __index metamethod itself: First, you probably meant t instead of table and rawget(t, key) instead of t[key] (which would cause infinite recursion).
But as lhf pointed out, the check is altogether unnecessary, because __index is only called when the key is not present in t. So you could just write:
__index = function(t, key)
return {}
end
One last remark:
I sometimes make small games in Lua, and often have to implement a 2D array
Why don't you implement it once and reuse it in other games? That's what modules are for!

Resources