How to prevent specified table content from being altered? - configuration

I got this (very simplified) scenario while coding a port handling routine for a micro-controller.
3 files
file1:
table = {var1 = true, var2 = true, var 3 = false, var 4 = true}
function dosomething()
dosomething
--defines bools in table by whatever condition is present
end
file2: Actually a Menu. If an input is given the corresponding boolean in table is changed.
function selection()
selection = interprete_input()
invertVars(selection)
end
function invertVars(selection)
table.selection = not table.selection
end
file3: in the simplified scenario, only uses the bools#table to know it to operate for the given case or not. The indices are used as values as well. For example one entry in table could be ' ["ttyS0"] = true ' so I know the function whether should run for COM-Port ttyS0 or not
function needsVarsFromTable()
for v,k in pairs(table)
if k then
--the actual function uses true/false as indicator to know if to run
--for the entry of table or not.
the_actual_function_that_needs_v(v)
end
end
The Problem now is:
The Table contains 19 entries. 2 of them have to be static. They're false and can never be true. But in my script it's possible to make them true what will cause errors.
Unfortunately Lua doesn't bring static variables. How can I prevent them from be altered by other functions? These other functions still have to be able to read them.
I don't want to check for every var#Table if the reading function is allowed to alter, due performance issue.

PiL 13.4.5 provides an example of read-only table, read the whole chapter if you are not familiar with metatables and metamethods.
To protect the field "var2", a little modification to the code in the book can do it:
local t = {var1 = true, var2 = true, var3 = false, var4 = true}
function protect_field(t)
local proxy = {}
local mt = { -- create metatable
__index = t,
__newindex = function (t, k, v)
if k == 'var2' then
error("attempt to update var2 field")
else
rawset(t, k, v)
end
end
}
setmetatable(proxy, mt)
return proxy
end
t = protect_field(t)
Now it's legal to update field "var1":
t.var1 = false
But t.var2 = false will raise an error.

Related

Can I use a value stored in a table as a key in another table?

I'm new to LUA and I still haven't gotten the hang of how classes work in LUA, so my question
probably has a very simple answer. I'm trying to make a function that takes a CSV file and turns it into a lua table.
The input file would be something like this
PropertyKey1,Propertykey2,Propertykey3
object1property1,object1property2,object1property3
object2property1,object2property2,object2property3
object3property1,object3property2,object3property3
and I want the resulting lua table to look something like this
objects = {
{
PropertyKey1 = object1property1
PropertyKey2 = object1property2
PropertyKey3 = object1property3
}
{
PropertyKey1 = object2property1
PropertyKey2 = object2property2
PropertyKey3 = object2property3
}
{
PropertyKey1 = object3property1
PropertyKey2 = object3property2
PropertyKey3 = object3property3
}
}
this is what I have thus far
function loadcsv(path)
local OutTable = {}
local file = io.open(path, "r")
local linecount = 0
for line in file:lines() do
local data = {}
local headers = {}
local headerkey = 1
if linecount < 1 then
for val in line:gmatch("([^,]+),?") do
table.insert(headers, val)
end
else
for word in line:gmatch("([^,]+),?") do
key = headers[headerkey]
data[headerkey] = word
headerkey = headerkey + 1
table.insert(OutTable, data)
end
end
linecount = linecount + 1
end
file:close()
return OutTable
end
The above code does not run. When I try to print any of the values, they come as nil.
The problem is this bit
key = headers[headerkey]
data[headerkey] = word
I wanted to use the values I stored in one table as keys on the second table, but it looks like since LUA only passes the references, that doesn't work.
I did a quick experiment to confirm it. I first set up 2 tables.
test = {}
test2 = {}
test[1]={"index"}
key = test[1]
key2 = "index"
First I tried assigning the value directly form the table
test2[test[1]] = "text"
print(test2.index) --This did not work
then I tried going trough another variable
test2[key] = "texto"
print(test2.index) --This did not work
I even tried using tostring()
key = tostring(test[1])
test2[key] = "texto"
print(test2.index) --This did not work
I wrote the string directly in the variable "key2" to confirm that I was using the right notation.
test2[key2] = "text"
print(test2.index) --This one worked
I read a bit on metatables, but I'm not fully clear on those. Would that be the simplest way to do what I'm trying to do, or is my approach flawed in some other way?
key = headers[headerkey]
key is not used so why assign a value to it?
data[headerkey] = word
headerkey is a numeric key. You start at 1 for each line and add 1 for each word in a line. So you end up with
data = {
[1] = "object1property1",
[2] = "object1property2",
[3] = "object1property3"
}
Instead of the intended
data = {
PropertyKey1 = "object1property1",
PropertyKey2 = "object1property2",
PropertyKey3 = "object1property3"
}
So you probably meant to write
local key = headers[headerkey]
data[key] = word
But you have to move headers out of the loop. Otherwise you'll end up with an empty table for line 1 resulting in key being nil which would cause Lua errors for using a nil table index.
The following line is called for every word
table.insert(OutTable, data)
You need to do this for every line!
Your code basically produces this output:
local tableA = {"object1property1", "object1property2", "object1property3"}
local tableB = {"object2property1", "object2property2", "object2property3"}
local tableC = {"object3property1", "object3property2", "object3property3"}
OutTable = {
tableA, tableA, tableA, tableB, tableB, tableB, tableC, tableC, tableC
}
I suggest you formulate your program in your first language and then translate it into Lua. This helps to avoid such errors.
Your problem is not related to metatables, classes or anything else mentioned. You simply used the wrong variable and messed up your inner loop.

Handling NULL = NULL comparisons in Access VBA

I have a problem with NULL = NULL returning NULL. I want it to return True. After a bit of research I found a line that I thought would work..
set ansi_nulls off
I quickly learned that Access doesn't recognize it. So here I am attempting to do nested conditions in Access and it's a complete nightmare.
Is there an easier way to handle this?
If you're doing a large amount of "equal or both null" comparisons, there are multiple solutions:
If you're OK with 0 = Null resulting to true when comparing numbers, or "" = Null resulting to true when comparing strings, you can use:
If Nz(Value1) = Nz(Value2) Then
This replaces all Nulls with 0 or "" dependent on the input type.
Consequences: Nz(Null) = Nz(Null) → True, 0 = Nz(Null) → True, "" = Nz(Null) → True, 1 = Nz(Null) → False, "a" = Nz(Null) → False
Create a user-defined function to do the comparison for you
The function:
Public Function CompareWithNulls(Value1 As Variant, Value2 As Variant) As Boolean
If IsNull(Value1) And IsNull(Value2) Then
CompareWithNulls = True
Else
CompareWithNulls = Value1 = Value2
End If
End Function
The use of the function:
If CompareWithNulls(Value1, Value2) Then
You can use the And keyword to test multiple conditions without nesting:
If IsNull(Value1) And IsNull(Value2) Then
You could create a method to compare two variables with a null check and then each IF only needs to call this function instead of the usual =

lua post hooking a function

I found one topic that's about post hooking, but I don't think it's the same thing as I want to accomplish. topic i found
What I need is the following:
local someBoolean = false
function doSomething() -- this is the function used in __index in a proxy table
someBoolean = true
return aFunction -- this is function that we can NOT alter
end
I need to ble able to run the code "someBoolean = false" after the return... (yes, I know that's not supposed to happen :p) considering aFunction may contain other functions itself, I want someBoolean to be true for the entire scope of aFunction, but after that, it HAS to be turned back to false
I'm sorry if I didn't manage to explain it well enough. Copy pasting the relevant code of my actual project would be way too large, and I don't want to waste your time.
I've been stuck on this for a while now, and I just can't seem to figure it out...
(edit: I can't just put someBoolean = false after the function, because the function is actually an __index function on a proxy table)
edit: relevent piece of code. I hope it's a bit clear
local function objectProxyDelegate(t, key)
if not done then -- done = true when our object is fully initialised
return cls[key] -- cls is the class, newinst is the new instance (duh...)
end
print("trying to delegate " .. key)
if accessTable.public[key] then
print(key .. " passed the test")
objectScope = true
if accessTable.static[key] then -- static function. return the static one
return cls[key] -- we need to somehow set objectScope back to false after this, otherwise we'll keep overriding protected/private functions
else
return newinst[key]
end
elseif objectScope then
print("overridden protected/private")
return cls[key]
end
if accessTable.private[key] then
error ("This function is not visible. (private)", 2)
elseif accessTable.protected[key] then
error ("This function is not visible to an instance. (protected)", 2)
else
error ("The function " .. key .. " doesn't exiist in " .. newinst:getType(), 2) -- den deze...
end
end
Since you need to return a function (rather than evaluate a function) you can create a proxy for the aFunction and return that instead. Here's how it could work (with a bunch of code taken from the solution by Nicol Bolas):
local someBoolean = false
function doSomething(...) -- this is the function used in __index in a proxy table
someBoolean = true
-- Return a proxy function instead of aFunction
return function(...)
local rets = { aFunction(...) }
someBoolean = false
return table.unpack(rets)
end
end
You cannot execute code after a return statement. The correct answer is to call the function, catch the return values, set the variable, and then return the return values. For example:
local someBoolean = false
function doSomething(...) -- this is the function used in __index in a proxy table
someBoolean = true
local rets = { aFunction(...) } -- this is function that we can NOT alter
someBoolean = false
return table.unpack(rets)
end

Reassigning Variables when Passing Structures to Functions in Matlab

I'm working with a series of MatLab functions that take 10+ single-value arguments. I've used structures to pass the arguments to keep the code readable. An example of a function header (input is a structure):
function output = myFunction(input)
I'm finding that typing the structure name throughout the code makes it more difficult to read:
calc1 = input.var1 * input.var2;
calc2 = input.var2 * input.var3;
I realize the example above could conveniently use an array, but most of my arguments are unrelated and of varying types. Additionally, the operations I'm carrying out on the variables are more complicated than the example above and don't lend themselves to an array.
I could create variable names to accept the values from the input structure:
function output = myFunction(input)
var1 = input.var1;
var2 = input.var2;
var3 = input.var3;
calc1 = var1 * var2;
calc2 = var2 * var3;
Doing this creates a long block at the top of the function which does nothing but reassign the input variables, and the data has to be copied so there is a performance penalty. On the other hand, the code is easier to read.
Is there any coding convention that could provide guidance? I've found plenty of resources here and on Google that suggest passing large amounts of data to MatLab functions using structures, but precious little on how to do so intelligently.
How about if you write a function that parses the input arguments, and design it so that it accepts either a structure as input, or a list of variables.
Example:
function output = myFunc(varargin)
narginchk(1,3);
[var1,var2,var3] = parseInput(varargin{:});
fprintf('var 1 = %g\n', var1);
fprintf('var 2 = %g\n', var2);
fprintf('var 3 = %g\n', var3);
output = var1+var2+var3;
end
function [var1,var2,var3] = parseInput(varargin)
if nargin == 1 && isstruct(varargin{1})
var1 = varargin{1}.var1;
var2 = varargin{1}.var2;
var3 = varargin{1}.var3;
elseif nargin == 3
[var1,var2,var3] = deal(varargin{:});
else
error('myFunc:parseInput', 'Incorrect input')
end
end
Now we can call the function as:
x = myFunc(1,2,3)
or:
in = struct('var1',1, 'var2',2, 'var3',3);
x = myFunc(in)
Of course you could add more strict validation to check the input (see validateattributes and InputParser)

Define default values for function arguments

In the Lua wiki I found a way to define default values for missing arguments:
function myfunction(a,b,c)
b = b or 7
c = c or 5
print (a,b,c)
end
Is that the only way? The PHP style myfunction (a,b=7,c=5) does not seem to work. Not that the Lua way doesn't work, I am just wondering if this is the only way to do it.
If you want named arguments and default values like PHP or Python, you can call your function with a table constructor:
myfunction{a,b=3,c=2}
(This is seen in many places in Lua, such as the advanced forms of LuaSocket's protocol modules and constructors in IUPLua.)
The function itself could have a signature like this:
function myfunction(t)
setmetatable(t,{__index={b=7, c=5}})
local a, b, c =
t[1] or t.a,
t[2] or t.b,
t[3] or t.c
-- function continues down here...
end
Any values missing from the table of parameters will be taken from the __index table in its metatable (see the documentation on metatables).
Of course, more advanced parameter styles are possible using table constructors and functions- you can write whatever you need. For example, here is a function that constructs a function that takes named-or-positional argument tables from a table defining the parameter names and default values and a function taking a regular argument list.
As a non-language-level feature, such calls can be changed to provide new behaviors and semantics:
Variables could be made to accept more than one name
Positional variables and keyword variables can be interspersed - and defining both can give precedence to either (or cause an error)
Keyword-only positionless variables can be made, as well as nameless position-only ones
The fairly-verbose table construction could be done by parsing a string
The argument list could be used verbatim if the function is called with something other than 1 table
Some useful functions for writing argument translators are unpack (moving to table.unpack in 5.2), setfenv (deprecated in 5.2 with the new _ENV construction), and select (which returns a single value from a given argument list, or the length of the list with '#').
In my opinion there isn't another way. That's just the Lua mentality: no frills, and except for some syntactic sugar, no redundant ways of doing simple things.
Technically, there's b = b == nil and 7 or b (which should be used in the case where false is a valid value as false or 7 evaluates to 7), but that's probably not what you're looking for.
The only way i've found so far that makes any sense is to do something like this:
function new(params)
params = params or {}
options = {
name = "Object name"
}
for k,v in pairs(params) do options[k] = v end
some_var = options.name
end
new({ name = "test" })
new()
If your function expects neither Boolean false nor nil to be passed as parameter values, your suggested approach is fine:
function test1(param)
local default = 10
param = param or default
return param
end
--[[
test1(): [10]
test1(nil): [10]
test1(true): [true]
test1(false): [10]
]]
If your function allows Boolean false, but not nil, to be passed as the parameter value, you can check for the presence of nil, as suggested by Stuart P. Bentley, as long as the default value is not Boolean false:
function test2(param)
local default = 10
param = (param == nil and default) or param
return param
end
--[[
test2(): [10]
test2(nil): [10]
test2(true): [true]
test2(false): [false]
]]
The above approach breaks when the default value is Boolean false:
function test3(param)
local default = false
param = (param == nil and default) or param
return param
end
--[[
test3(): [nil]
test3(nil): [nil]
test3(true): [true]
test3(false): [false]
]]
Interestingly, reversing the order of the conditional checks does allow Boolean false to be the default value, and is nominally more performant:
function test4(param)
local default = false
param = param or (param == nil and default)
return param
end
--[[
test4(): [false]
test4(nil): [false]
test4(true): [true]
test4(false): [false]
]]
This approach works for reasons that seem counter-intuitive until further examination, upon which they are discovered to be kind of clever.
If you want default parameters for functions that do allow nil values to be passed, you'll need to do something even uglier, like using variadic parameters:
function test5(...)
local argN = select('#', ...)
local default = false
local param = default
if argN > 0 then
local args = {...}
param = args[1]
end
return param
end
--[[
test5(): [false]
test5(nil): [nil]
test5(true): [true]
test5(false): [false]
]]
Of course, variadic parameters completely thwart auto-completion and linting of function parameters in functions that use them.
Short answer is that it's simplest and best way . in lua , variables by default equal with nil . this means if we don't pass argument to lua functions ,the argument is exits but is nil and lua programmers uses of this lua attribute for set the default value .
also it's not a way for set default value but you can use following function
this function create a error is you don't pass values to arguments
function myFn(arg1 , arg2)
err = arg1 and arg2
if not err then error("argument") end
-- or
if not arg1 and arg2 then error("msg") end
but it's not a good way and better is don't use of this function
and in diagrams shows optional argument in [,arg]
function args(a1 [,a2])
-- some
end
function args ( a1 [,a2[,a3]])
-- some
end
As always, "Lua gives you the power, you build the mechanisms". The first distinction to make here is that between named parameters and the commonly used parameter list.
The parameter list
Assuming all your args are given in the parameter list as follows, they will all be initialized. At this point, you can't distinguish between "wasn't passed" and "was passed as nil" - both will simply be nil. Your options for setting defaults are:
Using the or operator if you expect a truthy value (not nil or false). Defaulting to something even if false is given might be a feature in this case.
Using an explicit nil check param == nil, used either as if param == nil then param = default end or the typical Lua ternary construct param == nil and default or param.
If you find yourself frequently repeating the patterns from point (2), you might want to declare a function:
function default(value, default_value)
if value == nil then return default_value end
return value
end
(whether to use global or local scope for this function is another issue I won't get into here).
I've included all three ways the following example:
function f(x, y, z, w)
x = x or 1
y = y == nil and 2 or y
if z == nil then z == 3 end
w = default(w, 4
print(x, y, z, w)
end
f()
f(1)
f(1, 2)
f(1, 2, 3)
f(1, 2, 3, 4)
note that this also allows omitting arguments inbetween; trailing nil arguments will also be treated as absent:
f(nil)
f(nil, 2, 3)
f(nil, 2, nil, 4)
f(1, 2, 3, nil)
Varargs
A lesser known feature of Lua is the ability to actually determine how many arguments were passed, including the ability to distinguish between explicitly passed nil arguments and "no argument" through the select function. Let's rewrite our function using this:
function f(...)
local n_args = select("#", ...) -- number of arguments passed
local x, y, z, w = ...
if n_args < 4 then w = 4 end
if n_args < 3 then z = 3 end
if n_args < 2 then y = 2 end
if n_args < 1 then x = 1 end
print(x, y, z, w)
end
f() -- prints "1 2 3 4"
f(nil) -- prints "nil 2 3 4"
f(1, nil) -- prints "1 nil 3 4"
f(1, nil, 3) -- prints "1 nil 3 4"
f(nil, nil, nil, nil) -- prints 4x nil
Caveat: (1) the argument list got dragged into the function, hurting readability (2) this is rather cumbersome to write manually, and should probably be abstracted away, perhaps time using a wrapper function wrap_defaults({1, 2, 3, 4}, f) that supplies the defaults as appropriate. Implementation of this is left up to the reader as an exercise (hint: the straightforward way would first collect the args into a garbage table, then unpack that after setting the defaults).
Table calls
Lua provides syntactic sugar for calling functions with a single table as the only argument: f{...} is equivalent to f({...}). Furthermore, {f(...)} can be used to capture a vararg returned by f (caveat: if f returns nils, the table will have holes in it's list part).
Tables also allow implementing named "arguments" as table fields: Tables allow mixing a list and a hash part, making f{1, named_arg = 2} perfectly valid Lua.
In terms of limitations, the advantage of table call is that it only leaves a single argument - the table - on the stack rather than multiple arguments. For recursive functions, this allows hitting the stack overflow later. Since PUC Lua drastically increased the stack limit to ~1M this isn't much of an issue anymore; LuaJIT still has a stack limit of ~65k however, and PUC Lua 5.1 is even lower at around 15k.
In terms of performance & memory consumption, the table call is obviously worse: It requires Lua to build a garbage table, which will then waste memory until the GC gets rid of it. Garbage parameter tables should therefore probably not be used in hotspots where plenty of calls happen. Indexing a hashmap is also obviously slower than getting values straight off the stack.
That said, let's examine the ways to implement defaults for tables:
Unpacking / Destructuring
unpack (table.unpack in later versions (5.2+)) can be used to convert a table into a vararg, which can be treated like a parameter list; note however that in Lua the list part can't have trailing nil values, not allowing you to distinguish "no value" and nil. Unpacking / destructuring to locals also helps performance since it gets rid of repeated table indexing.
function f(params)
local x, y, z, w = unpack(params)
-- use same code as if x, y, z, w were regular params
end
f{1, 2, nil}
if you use named fields, you'll have to explicitly destructure those:
function f(params)
local x, y, z, w = params.x, params.y, params.z, params.w
-- use same code as if x, y, z, w were regular params
end
f{x = 1, w = 4}
mix & match is possible:
function f(params)
local x, y, z = unpack(params)
local w = params.w
-- use same code as if x, y, z, w were regular params
end
f{1, 2, w = 4}
Metatables
The __index metatable field can be used to set a table which is indexed with name if params.name is nil, providing defaults for nil values. One major drawback of setting a metatable on a passed table is that the passed table's metatable will be lost, perhaps leading to unexpected behavior on the caller's end. You could use getmetatable and setmetatable to restore the metatable after you're done operating with the params, but that would be rather dirty, hence I would recommend against it.
Bad
function f(params)
setmetatable(params, {__index = {x = 1, y = 2, z = 3, w = 4}})
-- use params.[xyzw], possibly unpacking / destructuring
end
f{x = 1}
in addition to the presumably garbage params table, this will create (1) a garbage metatable and (2) a garbage default table every time the function is called. This is pretty bad. Since the metatable is constant, simply drag it out of the function, making it an upvalue:
Okay
local defaults_metatable = {__index = {x = 1, y = 2, z = 3, w = 4}}
function f(params)
setmetatable(params, defaults_metatable)
-- use params.[xyzw], possibly unpacking / destructuring
end
Avoiding metatables
If you want a default table without the hackyness of metatables, consider once again writing yourself a helper function to complete a table with default values:
local function complete(params, defaults)
for param, default in pairs(defaults) do
if params[param] == nil then
params[param] = default
end
end
end
this will change the params table, properly setting the defaults; use as params = complete(params, defaults). Again, remember to drag the defaults table out of the function.